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
FnMutclosure also implementsFnOnce. - Every
Fnclosure automatically implementsFnMut. - A closure that mutates captured variables implements
FnMutandFnOnce, but notFn.
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