Search code examples
rustreferenceclosuresborrow-checker

Why isn't reborrow occured when using it with closures?


Here is the example:

fn bar<T>(v: &mut Vec<T>) {
    bar(v); //reborrows
    bar(v); //reborrows
}

which compiles fine. But consider slightly modified version:

fn foo<T>(v: &mut Vec<T>) {
    let mut f = ||{
        foo(v);
    };
    let mut g = ||{
        foo(v);
    };
    f();
    g();
}

What we have here is compile error:

error[E0524]: two closures require unique access to `*v` at the same time
 --> src/lib.rs:5:17
  |
2 |     let mut f = ||{
  |                 -- first closure is constructed here
3 |         foo(v);
  |             - first borrow occurs due to use of `*v` in closure
4 |     };
5 |     let mut g = ||{
  |                 ^^ second closure is constructed here
6 |         foo(v);
  |             - second borrow occurs due to use of `*v` in closure
7 |     };
8 |     f();
  |     - first borrow later used here

Playground

I guess the error message related to having multiple mutable references at the same time. But in the first example there's multiple references at the same time as well. This is very confusing.


Solution

  • In the first case, each reborrow is created before function call and destroyed immediately afterwards, without coexisting. Yes, they have the same lexical scope, but without interleaved usage.

    In the second case, though, reborrows are created when closures are created - this action is not deferred until the call, so the creation of g invalidates the reborrow captured by f, and therefore invalidates f itself.