I don't quite understand why the following 2 closure variations behave differently:
#1 mutable borrow environment capture
let mut vec = vec![1, 2, 3];
let mut f = |x| { vec.push(x); };
f(4);
println!("{:?}", vec);
f(5);
println!("{:?}", vec);
#2 mutable borrow parameter
let mut vec = vec![1, 2, 3];
let f = |v: &mut Vec<usize>, x| { v.push(x); };
f(&mut vec, 4);
println!("{:?}", vec);
f(&mut vec, 5);
println!("{:?}", vec);
Since the closure does not return any reference, I initially expected the borrow of vec
to behave the same way in both variations. However, while #2 works fine, #1 fails to compile with:
let mut f = |x| { vec.push(x); };
--- --- first borrow occurs due to use of `vec` in closure
|
mutable borrow occurs here
f(4);
println!("{:?}", vec);
^^^ immutable borrow occurs here
f(5);
- mutable borrow later used here
I noticed that if I remove the call to f(5)
then both examples work. I think I vaguely understand that this is related to the following explanation in the book: Closures: Anonymous Functions that Capture Their Environment - The Rust Programming Language ("Between the closure definition and the closure call, an immutable borrow to print isn’t allowed because no other borrows are allowed when there’s a mutable borrow.")
But I'm confused on these 2 points:
- Why does the mutable borrow need to be "alive" before the closure is called?
- If the compiler were to allow #1, is there any way to make analogous changes in both variations such that #2 is still valid while #1 has some invalid/undefined behavior? (If the answer is "no", I would conclude this falls into the "reject some correct programs but never accept incorrect programs" case.)