capypad
0 day streak
rust / intermediate
Snippet

Understanding Rust Closures: Fn, FnMut, and FnOnce

Rust closures are anonymous functions that capture their environment. The three closure traits represent different ownership behaviors: Fn borrows immutably, FnMut borrows mutably, and FnOnce takes ownership. Understanding these traits is crucial for writing higher-order functions and efficient callback 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
28
29
30
31
32
33
34
fn main() {
let x = 10;
 
// Fn: borrows values immutably
let print_x = || println!("x = {}", x);
print_x();
 
// FnMut: mutably borrows values
let mut counter = 0;
let mut increment = || {
counter += 1;
println!("Counter: {}", counter);
};
increment();
 
// FnOnce: consumes values (takes ownership)
let data = vec![1, 2, 3];
let consume_data = || {
println!("Data: {:?}", data);
// data is moved here
};
consume_data();
 
// Higher-order function taking closures
let result = apply_twice(5, |n| n * n);
println!("Result: {}", result);
}
 
fn apply_twice<F>(value: i32, f: F) -> i32
where
F: Fn(i32) -> i32,
{
f(f(value))
}
Breakdown
1
let print_x = || println!("x = {}", x);
A closure that borrows x immutably - implements Fn trait
2
let mut increment = || { counter += 1; ...
A closure that mutably borrows counter - implements FnMut trait
3
let consume_data = || { println!("{:?}", data);
A closure that moves data into itself - implements FnOnce trait
4
where F: Fn(i32) -> i32
Generic bound specifying the closure type that apply_twice accepts