Closures
Capture by Shared Reference
When a closure only reads a variable from its enclosing scope without mutating or moving it, the compiler captures that variable by shared reference (&T).
How Shared Reference Capture Works
Capturing x by shared reference stores &x inside the closure. While the closure borrow is active (between the closure's creation and its final use), the outer scope follows standard borrowing rules for shared references:
- The outer scope can continue to read
xor create additional shared references&x. - The outer scope cannot mutate
x(&mut x) or movexuntil after the last time the closure is called.
fn main() {
let numbers = vec![10, 20, 30];
// Captures `&numbers` because `.len()` and indexing only read `numbers`:
let report = || println!("Len = {}, first = {}", numbers.len(), numbers[0]);
// Reading `numbers` in the outer scope while `report` is alive is allowed:
println!("Outer read before call: {:?}", numbers);
report();
report();
}
Outer read before call: [10, 20, 30]
Len = 3, first = 10
Len = 3, first = 10
Non-Lexical Lifetimes (NLL) After the Final Call
Once a closure that captures &x has been called for the last time, its shared borrow of x ends immediately—even before the end of the enclosing block—allowing x to be mutated afterward:
fn main() {
let mut items = vec![1, 2, 3];
let print_len = || println!("Current len: {}", items.len());
print_len(); // Last use of `print_len` — shared borrow ends here
// Mutating `items` is now valid:
items.push(4);
println!("After push: {items:?}");
}
Current len: 3
After push: [1, 2, 3, 4]
Borrow Conflict When Mutating While Closure Is Still Live (E0502)
If the outer scope attempts to mutate a variable between the creation of a shared-capturing closure and a subsequent call to that closure, the borrow checker rejects the code with E0502:
// ❌ does not compile
fn main() {
let mut items = vec![1, 2, 3];
let print_len = || println!("Current len: {}", items.len());
items.push(4); // Error: mutable borrow while `print_len` holds `&items`
print_len();
}
error[E0502]: cannot borrow `items` as mutable because it is also borrowed as immutable
--> src/main.rs:7:5
|
5 | let print_len = || println!("Current len: {}", items.len());
| -- ----- first borrow occurs due to use of `items` in closure
| |
| immutable borrow occurs here
6 |
7 | items.push(4);
| ^^^^^^^^^^^^^ mutable borrow occurs here
8 |
9 | print_len();
| --------- immutable borrow later used here