Essential Standard Traits
Fn, FnMut, and FnOnce
The Fn, FnMut, and FnOnce traits in std::ops represent callable values (closures and function pointers), classified by how they access variables captured from their enclosing environment.
Trait Hierarchy
The three callable traits form a strict supertrait hierarchy:
FnOnce (consumes self; can be called at least once)
▲
│ supertrait
FnMut (takes &mut self; can mutate captured state)
▲
│ supertrait
Fn (takes &self; reads captured state immutably)
Because Fn: FnMut and FnMut: FnOnce:
- Every
Fnclosure also implementsFnMutandFnOnce. - Every
FnMutclosure also implementsFnOnce. - Plain function pointers (
fn(A) -> R) and non-capturing closures implement all three:Fn,FnMut, andFnOnce.
How Capture Mode Determines Implemented Traits
The compiler automatically implements the most permissive traits possible for a closure based on what the closure body does with its captured variables:
| What the Closure Body Does with Captures | Receiver | Traits Implemented |
|---|---|---|
Does not capture, or only reads captures (&T) |
&self |
Fn, FnMut, FnOnce |
Mutates at least one captured variable (&mut T), moves none out |
&mut self |
FnMut, FnOnce |
Moves a non-Copy captured value out of the closure |
self |
FnOnce only |
fn call_once<F: FnOnce() -> String>(f: F) -> String {
f()
}
fn call_mut<F: FnMut()>(mut f: F) {
f();
f();
}
fn call_immut<F: Fn() -> usize>(f: F) -> usize {
f() + f()
}
fn main() {
let label = String::from("metrics");
// 1. Only reads `label` -> implements Fn + FnMut + FnOnce
let reader = || label.len();
println!("Read twice: {}", call_immut(reader));
// 2. Mutates `counter` -> implements FnMut + FnOnce
let mut counter = 0;
call_mut(|| counter += 1);
println!("Counter after call_mut: {counter}");
// 3. Moves `label` out of environment -> implements FnOnce only
let consumer = || {
let owned = label;
owned + "_done"
};
println!("Consumed: {}", call_once(consumer));
}
Read twice: 14
Counter after call_mut: 2
Consumed: metrics_done
Choosing a Closure Bound in Function Signatures
When writing a higher-order function that accepts a callback:
- Prefer
FnOnceif the function invokes the callback at most once (for example,Option::unwrap_or_else), as it accepts all closures. - Use
FnMutif the function invokes the callback multiple times sequentially (for example,Iterator::maporslice::sort_by), allowing callers to maintain mutable state across calls. - Use
Fnonly when the callback must be called concurrently from multiple threads or aliased through shared references.