Rust
Beginner
1 min read
Fn, FnMut, and FnOnce Traits
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));
}