fn main() {
let mut a = Vec::new();
let mut foo = Foo::new(|v| {
for i in v {
a.push(i);
}
});
foo.fun(1);
println!("{:?}", a);
}
results in a compilation error:
error[E0502]: cannot borrow `a` as immutable because it is also borrowed as mutable
--> src/main.rs:24:22
|
18 | let mut foo = Foo::new(|v| {
| --- mutable borrow occurs here
19 | for i in v {
20 | a.push(i);
| - first borrow occurs due to use of `a` in closure
...
24 | println!("{:?}", a);
| ^ immutable borrow occurs here
25 | }
| - mutable borrow might be used here, when `foo` is dropped and runs the destructor for type `Foo<'_, i32>`
which means that the lifetime of foo ends after println!("{:?}", a);, showing that foo here follows lexical rules instead of NLL.
Why is the difference, and how exactly NLL for struct works?
The difference is that the second case uses a type with a destructor (Box<T>). The destructor runs when the owner goes out of scope. (Destructors always follow simple scope-based rules; they don't change based on how a value is used.) So the borrow must live for the entire scope.
...but you can explicitly change where it goes out of scope by using drop(foo); before the println!() (for example). The difference is maintained for the sake of backwards compatibility (pre-NLL code may have relied on destructors running when they did).
But Vecimplements Drop (which means it has destructor as well?). And in the first code example foo has a Vec field. So foo's lifetime should also be lexical?
Foo and Bar don't implement Drop though -- compiler generated "drop glue", which is not a Drop implementation, recursively drops the members. I'd link you to documentation explaining this, but as far as I know, there is no official documentation which covers all of these details.
(If you impl Drop for your structs, you will get a similar error.)