Closure Traits: Fn, FnMut, FnOnce
In this page:
fn name<F: Fn(Param) -> Ret>(f: F) {} // borrows
fn name<F: FnMut(Param) -> Ret>(mut f: F) {} // mutates
fn name<F: FnOnce() -> Ret>(f: F) {} // consumes
Fn: Read-Only Captures
A closure that only reads captured variables implements Fn, and can be called multiple times without any restriction.
Example: Fn: Read-Only Captures
// Entry point: execution of the program starts here
fn main() {
// Declare an immutable variable `greeting`, set to `String::from("Hello")`
let greeting = String::from("Hello");
// Declare an immutable variable `greet`, set to `|| println!("{}, world!", greeting)`
let greet = || println!("{}, world!", greeting);
greet();
greet();
}
Login to try C/C++/Java/PHP code in the editor
FnMut: Mutating Captures
A closure that mutates a captured variable implements FnMut; the variable holding the closure must itself be mut to call it.
Example: FnMut: Mutating Captures
// Entry point: execution of the program starts here
fn main() {
// Declare a mutable variable `count`, initialized to `0`
let mut count = 0;
// Declare a mutable variable `increment`, initialized to `|| {`
let mut increment = || {
count += 1;
// Print "count is now {}" to the console, substituting in `count` (with a trailing newline)
println!("count is now {}", count);
};
increment();
increment();
}
Login to try C/C++/Java/PHP code in the editor
FnOnce: Consuming Captures
A closure that moves a captured variable out of itself (for example, returning owned data) implements only FnOnce, meaning it can be called at most one time.
Example: FnOnce: Consuming Captures
// Entry point: execution of the program starts here
fn main() {
// Declare an immutable variable `text`, set to `String::from("consumed")`
let text = String::from("consumed");
// Declare an immutable variable `consume`, set to `move || {`
let consume = move || {
// Declare an immutable variable `owned`, set to `text`
let owned = text;
// Print "Consumed inside closure: {}" to the console, substituting in `owned` (with a trailing newline)
println!("Consumed inside closure: {}", owned);
};
consume();
}
Login to try C/C++/Java/PHP code in the editor
Forcing Ownership with move
The move keyword forces a closure to take ownership of every variable it captures, rather than borrowing them, which is required when the closure needs to outlive its original scope.
Example: Forcing Ownership with move
// Entry point: execution of the program starts here
fn main() {
// Declare an immutable variable `data`, set to `vec![1, 2, 3]`
let data = vec![1, 2, 3];
// Declare an immutable variable `owns_data`, set to `move || println!("Owned inside closure: {:?}", data)`
let owns_data = move || println!("Owned inside closure: {:?}", data);
owns_data();
}
Login to try C/C++/Java/PHP code in the editor
- Trying to call an
FnOnceclosure more than once -- by definition it can only be called a single time. - Requiring
Fnin a function signature when the closure passed actually needs to mutate captured state, requiringFnMutinstead. - Forgetting the
movekeyword forces a closure to take ownership of captured variables instead of borrowing them.
Fnclosures can be called repeatedly and only borrow captured variables immutably.FnMutclosures can be called repeatedly and may mutate captured variables.FnOnceclosures can only be called once, since they consume (move) captured variables.- The
movekeyword forces a closure to take ownership of the variables it captures rather than borrowing them.
Chapter Quiz — Complete all 6 topics to unlock
0/6 topics done
Complete these topics first: