capypad
0 day streak
rust / intermediate
Snippet

Understanding Fn, FnMut, and FnOnce Traits

Rust closures implement one of three traits based on how they use captured variables. FnOnce consumes captures, FnMut mutates them, and Fn borrows immutably. Functions can accept closures with trait bounds, enabling flexible functional patterns.

snippet.rs
rust
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
fn apply<F>(func: F, value: i32) -> i32
where
F: Fn(i32) -> i32,
{
func(value)
}
 
fn apply_twice<F>(mut func: F, value: i32) -> i32
where
F: FnMut(i32) -> i32,
{
func(func(value))
}
 
fn main() {
let x = 10;
let print_and_return = || {
println!("Captured: {}", x);
x
};
println!("Result: {}", apply(print_and_return, 5));
let mut counter = 0;
let mut increment = || { counter += 1; counter };
println!("Counter: {}", apply_twice(increment, 0)); // 2
}
Breakdown
1
F: Fn(i32) -> i32
Fn trait - closure borrows captures immutably, can be called multiple times
2
F: FnMut(i32) -> i32
FnMut trait - closure mutates captures, can be called multiple times
3
|| { println!("{}", x); x }
Captures x by reference - implements Fn, not FnOnce
4
|| { counter += 1; counter }
Mutates counter - implements FnMut