重构搞砸了可变借用——为什么?
Refactoring messes up mutable borrow - why?
我试图理解为什么以下重构会导致错误,即使它实际上应该具有相同的行为:
之前:
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
相同的生命周期。它也没有移动,只是作为 &mut
传递。那么是什么阻止了请求被使用?
为什么本地req
和函数参数都是引用时,错误说*req
被借用了?
生命周期注解的意思其实就是这样。如果你有一个具有这个原型的函数:
fn get_bar<'a>(&'a Foo) -> Bar<'a> { ... }
这意味着返回的 Bar
对象拥有与 Foo
对象之一绑定的生命周期。结果:
Bar
对象只要活着就借Foo
对象
Bar
对象的寿命不允许超过 Foo
对象。
在你的例子中,connection
是 PooledConnection<'a, ...>
类型,其中 'a
是 &'a mut req
中定义的生命周期,因此它被认为是 PooledConnection<'a, ...>
的可变借用=21=].
它在重构之前工作,因为 connection
的生命周期实际上与 pool
的生命周期相关联,pool
没有借用 req
因为它没有任何生命周期参数.
由于你的重构强制connection
借用req
,这在以前是不需要的,也许这不是一个合适的重构。
我试图理解为什么以下重构会导致错误,即使它实际上应该具有相同的行为:
之前:
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
相同的生命周期。它也没有移动,只是作为 &mut
传递。那么是什么阻止了请求被使用?
为什么本地req
和函数参数都是引用时,错误说*req
被借用了?
生命周期注解的意思其实就是这样。如果你有一个具有这个原型的函数:
fn get_bar<'a>(&'a Foo) -> Bar<'a> { ... }
这意味着返回的 Bar
对象拥有与 Foo
对象之一绑定的生命周期。结果:
Bar
对象只要活着就借Foo
对象Bar
对象的寿命不允许超过Foo
对象。
在你的例子中,connection
是 PooledConnection<'a, ...>
类型,其中 'a
是 &'a mut req
中定义的生命周期,因此它被认为是 PooledConnection<'a, ...>
的可变借用=21=].
它在重构之前工作,因为 connection
的生命周期实际上与 pool
的生命周期相关联,pool
没有借用 req
因为它没有任何生命周期参数.
由于你的重构强制connection
借用req
,这在以前是不需要的,也许这不是一个合适的重构。