Closures

The FnMut Trait

The FnMut trait in std::ops represents closures and functions that can be called repeatedly through an exclusive mutable reference (&mut self), allowing the closure to mutate variables in its captured environment across calls.

Conceptual Definition

pub trait FnMut<Args>: FnOnce<Args> {
    extern "rust-call" fn call_mut(&mut self, args: Args) -> Self::Output;
}

Because FnMut sits between Fn and FnOnce in the trait hierarchy (Fn: FnMut: FnOnce):

  • Every FnMut closure also implements FnOnce.
  • Every Fn closure automatically implements FnMut.
  • A closure that mutates captured variables implements FnMut and FnOnce, but not Fn.

Stateful Closures with FnMut

Closures that maintain an internal accumulator, counter, or buffer across multiple invocations implement FnMut:

fn apply_to_slice<F>(slice: &mut [i32], mut f: F)
where
    F: FnMut(usize, i32) -> i32,
{
    for (idx, val) in slice.iter_mut().enumerate() {
        *val = f(idx, *val);
    }
}

fn main() {
    let mut running_sum = 0;
    let mut data = [10, 20, 30, 40];

    // Mutates `running_sum` on each call -> implements `FnMut`
    apply_to_slice(&mut data, |_idx, x| {
        running_sum += x;
        running_sum
    });

    println!("Prefix sums: {data:?}");
    println!("Final total: {running_sum}");
}
Prefix sums: [10, 30, 60, 100]
Final total: 100

Mutating Owned Captures Inside a move Closure

A move closure that takes ownership of a variable and mutates its own internal copy across calls also implements FnMut:

fn make_id_generator(start: u64) -> impl FnMut() -> u64 {
    let mut current = start;
    move || {
        let id = current;
        current += 1;
        id
    }
}

fn main() {
    let mut next_id = make_id_generator(1000);
    println!("ID 1: {}", next_id());
    println!("ID 2: {}", next_id());
    println!("ID 3: {}", next_id());
}
ID 1: 1000
ID 2: 1001
ID 3: 1002

Rejecting an FnMut Closure Where Fn Is Required (E0525)

Passing a closure that mutates its environment to an API expecting Fn fails with E0525:

// ❌ does not compile
fn require_immutable_fn<F: Fn()>(f: F) {
    f();
}

fn main() {
    let mut count = 0;
    require_immutable_fn(|| count += 1);
}
error[E0525]: expected a closure that implements the `Fn` trait, but this closure only implements `FnMut`
 --> src/main.rs:8:26
  |
8 |     require_immutable_fn(|| count += 1);
  |     -------------------- ^^ ---------- closure is `FnMut` because it mutates the variable `count` here
  |     |                    |
  |     |                    this closure implements `FnMut`, not `Fn`
  |     required by a bound introduced by this call