【问题标题】:Refactoring messes up mutable borrow - why?重构搞砸了可变借用——为什么?
【发布时间】:2015-05-15 05:24:09
【问题描述】:

我试图理解为什么以下重构会导致错误,即使它实际上应该具有相同的行为:

之前:

fn req_handler(req: &mut Request) -> IronResult<Response> {
    let pool = req.get::<Read<Database>>().ok().expect("database component not initialised");
    let connection = pool.get().unwrap();

    let maybe_id = req.extensions.get::<Router>().unwrap().find("id");
    ...

之后:

pub fn get_pool_connection<'a, 'b, 'c>(req: &'a mut Request<'b, 'c>) -> PooledConnection<'a, PostgresConnectionManager> {
    let pool = req.get_ref::<Read<Database>>().ok().expect("database component not initialised");
    pool.get().unwrap()
}
fn req_handler(req: &mut Request) -> IronResult<Response> {
    let connection = get_pool_connection(req);
    let maybe_id = req.extensions.get::<Router>().unwrap().find("id");

这会导致错误:

src/main.rs:64:20: 64:34 error: cannot borrow `req.extensions` as immutable because `*req` is also borrowed as mutable
src/main.rs:64     let maybe_id = req.extensions.get::<Router>().unwrap().find("id");
                                  ^~~~~~~~~~~~~~
src/main.rs:62:42: 62:45 note: previous borrow of `*req` occurs here; the mutable borrow prevents subsequent moves, borrows, or modification of `*req` until the borrow ends
src/main.rs:62     let connection = get_pool_connection(req);
                                                        ^~~
src/main.rs:76:2: 76:2 note: previous borrow ends here
src/main.rs:61 fn req_handler(req: &mut Request) -> IronResult<Response> {
...
src/main.rs:76 }

所以问题是get_pool_connection 借用请求并返回connection,这阻止了req 的进一步使用。但是为什么会这样呢? req 保证使用至少与返回的 PooledConnection 相同的生命周期。它也没有被移动,它只是作为&amp;mut 传递的。那么是什么阻止了请求被使用呢?

当本地req和函数参数都是引用时,为什么错误说*req被借用了?

(相关文档:RequestPool

【问题讨论】:

  • 错误说 *req 是借用的,因为 req 是一个引用。毕竟,您通常借用一些拥有的数据作为参考点,而不是参考本身。

标签: rust lifetime


【解决方案1】:

这实际上正是生命周期注释的含义。如果你有一个具有这个原型的函数:

fn get_bar<'a>(&'a Foo) -> Bar<'a> { ... }

这意味着返回的Bar 对象拥有与Foo 对象相关联的生命周期。结果:

  • Bar 对象借用 Foo 对象,只要它还活着
  • Bar 对象的寿命不能超过Foo 对象。

在你的例子中,connectionPooledConnection&lt;'a, ...&gt; 类型,其中'a&amp;'a mut req 中定义的生命周期,因此它被视为req 的可变借用。

它在重构之前有效,因为connection 的生命周期实际上与pool 的生命周期相关联,它没有借用req,因为它不包含任何生命周期参数。

由于您的重构迫使connection 借用req,这是以前不需要的,也许它不是一个合适的重构。

【讨论】:

  • 有没有办法返回连接并使重构工作?还是在这种情况下我也必须归还游泳池?
  • 您将很难同时返回池和连接,因为它们的生命周期是捆绑在一起的。在这种只将两行代码重构为一个函数的精确案例中,我认为没有比不重构更好的解决方案了。
猜你喜欢
  • 1970-01-01
  • 2012-05-11
  • 1970-01-01
  • 2018-11-05
  • 2012-02-29
  • 1970-01-01
  • 1970-01-01
  • 2014-04-28
  • 2016-02-11
相关资源
最近更新 更多