Skip to main content

Documentation Index

Fetch the complete documentation index at: https://docs.syntblaze.com/llms.txt

Use this file to discover all available pages before exploring further.

FnOnce is a trait implemented by all closures in Rust, specifically representing closures that can be called at least once. When a closure strictly implements FnOnce (and not its subtraits FnMut or Fn), it means the closure consumes the variables it captures from its enclosing environment, taking ownership of them. Because the environment is consumed during execution, the closure cannot be invoked a second time.

Trait Signature

The mechanics of FnOnce are defined by its trait signature in the standard library:
pub trait FnOnce<Args> {
    type Output;
    fn call_once(self, args: Args) -> Self::Output;
}
The defining characteristic here is the self receiver in call_once. Unlike FnMut (which takes &mut self) or Fn (which takes &self), FnOnce takes self by value. This moves the closure instance—and its captured environment—into the method, consuming it entirely.

Execution Mechanics

A closure is inferred by the compiler to be strictly FnOnce if the body of the closure moves a captured variable out of the closure’s internal state. This typically happens when the closure drops the value, returns it, or passes it to another function that requires ownership.
let data = String::from("environment data");

// The compiler infers this closure as strictly `FnOnce`
let consume_closure = || {
    // `data` is moved out of the closure's environment into `_consumed`
    let _consumed = data; 
};

consume_closure(); // `call_once(self)` is executed, consuming the closure.

// consume_closure(); // COMPILER ERROR: closure cannot be invoked more than once

Trait Hierarchy

In Rust’s closure trait hierarchy, FnOnce is the foundational supertrait:
  • FnMut requires FnOnce (trait FnMut: FnOnce)
  • Fn requires FnMut (trait Fn: FnMut)
Because of this hierarchy, all closures implement FnOnce. If a function signature bounds a generic parameter to F: FnOnce, it dictates how the receiving function will use the closure (it promises to call it at most once). Consequently, a bound of FnOnce is the most permissive bound, accepting closures that are strictly FnOnce, as well as FnMut and Fn closures.
// This function accepts ANY closure, because all closures implement FnOnce.
fn execute_once<F>(closure: F)
where
    F: FnOnce(),
{
    closure();
}

Distinction from the move Keyword

A common misconception is that the move keyword dictates whether a closure is FnOnce. The move keyword only dictates how the closure captures variables (forcing by-value capture instead of by-reference). It does not dictate how the closure executes. A closure can use the move keyword to take ownership of a variable, but if it only reads or mutates that variable internally without moving it out of the closure body, it will still implement Fn or FnMut. FnOnce is strictly determined by whether the closure’s execution consumes the captured state.
let data = String::from("data");

// Uses `move`, but does not consume `data` during execution.
// Therefore, it implements `Fn` (and by extension, `FnOnce`).
let print_closure = move || {
    println!("{}", data); 
};

print_closure();
print_closure(); // Valid, because it is not strictly FnOnce
Master Rust with Deep Grasping Methodology!Learn More