Refactoring will spoil volatile debt - why?

I'm trying to figure out why the following refactoring results in an error, even though it should effectively have the same behavior:

Before:

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");
    ...

      

After:

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");

      

This results in an error:

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 }

      

So the problem is that the get_pool_connection

request is borrowed and returned connection

, which prevents further use req

. But why is this happening? req

guaranteed to use at least the same lifetime as the returned one PooledConnection

. He didn't move either, he just passed on like &mut

. So what's stopping you from using a query?

And why does the error say it *req

was borrowed when both the local req

and the function parameter are references?

(relevant docs: Request , Pool )

+3


source to share


1 answer


This is actually exactly the meaning of life annotations. If you have a function that has this prototype:

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

      

This means that the returned object Bar

has a resource bound to one of the objects Foo

. Consequently:

  • Objects Bar

    borrow the object Foo

    while it is alive.
  • The object is Bar

    not allowed to survive the object Foo

    .


In your case connection

has a type PooledConnection<'a, ...>

, where 'a

is the lifetime defined in &'a mut req

, so it is treated as mutable borrowing req

.

It worked before the refactoring because the lifetime is connection

actually related to the lifetime pool

, which did not take req

since it does not contain any lifetime parameter.

How do your refactoring forces connection

borrow req

that weren't needed before, it might not be appropriate refactoring.

+2


source







All Articles