Capturing a copy of a local variable for a lambda

I think it's worth noting that the fact that this program fails to compile whereas the analogous Python runs but gives the wrong answer is exactly what Rust's ownership and borrowing system is about. Prior languages gave you either the ability to accidentally use invalid pointers (C, C++, etc.) or implicitly shared pointers (Python, Java, etc.). Rust, by sticking to only exclusive mutability (except when explicitly opted out of), prevents this mistake (using i in the closure after it has been mutated elsewhere) by default.

(The particular error happened to be about & reference lifetimes, not borrow conflicts, but Rust wouldn't have & that works the way it does if it weren't for the ownership system.)

Of course, there are also other ways to solve this particular problem. Python's for could have had semantics which declare a new i variable (which each closure would capture separately) instead of the loop iterations assigning to a single existing variable.

But i shouldn't be borrowed here. Unless just copying the value of i into x borrows it?

Non-move closures always take the least powerful kind of capture (& borrow < &mut borrow < move) they can. Copying a value only requires a & borrow, so that's what it picks. If i was of a type that does not implement Copy (say, a String), then it would have been moved instead.

As already mentioned, using a move closure is the solution. Beyond that, sometimes one finds the need to write explicit variable declarations to control exactly what a closure captures, somewhat like you tried — but the key is that to be effective, those must be written outside the closure, not inside, and the closure must (for most of the cases where this arises) be a move closure. That would look like:

        vec.push({
            let x = i.clone();
            move || println!("message {}", x)
        });

In this case, there's no reason to do that, since i is Copy and the move closure suffices to handle that — but I thought I'd mention this common pattern that you almost stumbled on.

13 Likes