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 x or create additional shared references &x.
  • The outer scope cannot mutate x (&mut x) or move x until 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