The difference lies in how many times a closure can be called and whether it mutates captured data: FnOnce can be called once, FnMut can be called multiple times and mutates captures, and Fn can be called multiple times without mutating captures.
// FnOnce: Consumes captures (called once)
let x = vec![1, 2, 3];
let f = || println!("{:?}", x);
// FnMut: Mutates captures (called many times)
let mut count = 0;
let mut f = || count += 1;
// Fn: Immutable captures (called many times)
let val = 5;
let f = || println!("{:?}", val);
In the ThreadPool example from listing-21-13, the execute method uses FnOnce because the job is sent to a thread and consumed exactly once:
pub fn execute<F>(&self, f: F)
where
F: FnOnce() + Send + 'static,
{
// Job is moved into the thread
}
If you need to call the closure repeatedly without changing state, use Fn. If you need to modify captured variables across calls, use FnMut. If the closure takes ownership of its captures, it is FnOnce.