SyntaxStudy
Sign Up
Rust Fn, FnMut, and FnOnce Traits
Rust Beginner 1 min read

Fn, FnMut, and FnOnce Traits

Rust classifies closures by how they capture their environment through three traits in a hierarchy. `FnOnce` is the most general — every closure implements it, and it allows the closure to consume captured values. A closure that moves a captured value out of itself can only be called once, because after the call the value is gone. `FnOnce` is a supertrait of both `FnMut` and `Fn`. `FnMut` is implemented by closures that do not consume captured values but may mutate them. They can be called multiple times. `Fn` is the most restrictive — implemented by closures that only read captured values (or capture nothing). A closure implementing `Fn` also implements `FnMut` and `FnOnce` due to the hierarchy. When accepting a closure as a function parameter, use the least restrictive bound that your function requires. Understanding these three traits is critical when storing closures in structs or passing them across thread boundaries. `std::thread::spawn` requires a `FnOnce + Send + 'static` closure — it must be callable once (thread entry point), safe to send to another thread, and not hold references to non-static data. Using `move` closures satisfies the lifetime requirement by moving all captured data into the closure.
Example
// Accept any closure that takes () and returns ()
fn call_once<F: FnOnce()>(f: F) { f(); }
fn call_mut<F: FnMut()>(mut f: F) { f(); f(); f(); }
fn call_fn<F: Fn(i32) -> i32>(f: &F, x: i32) -> i32 { f(x) }

// Fn — only reads captured data (can be called many times)
fn make_greeter(name: String) -> impl Fn() {
    move || println!("Hello, {name}!")
}

// FnMut — mutates captured data
fn make_counter() -> impl FnMut() -> u32 {
    let mut count = 0u32;
    move || { count += 1; count }
}

// FnOnce — consumes captured data (can only be called once)
fn consume_string(s: String) -> impl FnOnce() -> usize {
    move || { println!("consuming: {s}"); s.len() }
}

fn main() {
    // Fn
    let greet = make_greeter("Rust".to_string());
    greet(); greet();   // called multiple times — ok for Fn

    // FnMut
    let mut counter = make_counter();
    println!("{}", counter()); // 1
    println!("{}", counter()); // 2
    println!("{}", counter()); // 3

    // FnOnce
    let get_len = consume_string("hello".to_string());
    let len = get_len();
    println!("len = {len}");
    // get_len(); // compile error: already consumed

    // call_once accepts any closure (FnOnce is the most permissive bound)
    call_once(|| println!("called once"));

    // call_mut requires FnMut
    let mut n = 0;
    call_mut(|| { n += 1; println!("n = {n}"); });

    // call_fn requires Fn — can pass &F to avoid consuming it
    let square = |x: i32| x * x;
    println!("square(4) = {}", call_fn(&square, 4));
    println!("square(5) = {}", call_fn(&square, 5));
}