Fn, FnMut, FnOnce
- Rust course
- Intermediate
- Lesson 45/115
- 4 min
Tell apart the three closure traits Fn, FnMut and FnOnce.
Fn, FnMut, FnOnce
Closures implement one (or several) of three traits depending on how they capture:
FnOnce— can be called at least once; may consume what it captured.FnMut— can be called many times, may change what it captured.Fn— can be called many times, only reads.
fn uygula<F: Fn(i32) -> i32>(f: F, x: i32) -> i32 { f(x) }
fn iki_kez<F: FnMut()>(mut f: F) { f(); f(); }
fn bir_kez<F: FnOnce() -> String>(f: F) -> String { f() }Every Fn is also FnMut, and every FnMut is also FnOnce.
Choosing the right bound
The bound is chosen by what the function will do with the closure:
let mut n = 0;
iki_kez(|| n += 3); // FnMut: changes n
println!("{n}"); // 6
let s = String::from("son");
println!("{}", bir_kez(move || s)); // FnOnce: returns and consumes s
println!("{}", uygula(|x| x + 10, 5)); // Fn: 15move || s can't be passed to iki_kez; s would no longer exist on the second call.
Practice Three traits
Write the functions uygula, iki_kez and bir_kez above. Print the results of uygula(|x| x + 10, 5), n after adding 3 twice, and bir_kez(move || s) (s = "son") separated by spaces.
Starter code
fn main() {
// buraya yaz
}Sample solution
fn uygula<F: Fn(i32) -> i32>(f: F, x: i32) -> i32 {
f(x)
}
fn iki_kez<F: FnMut()>(mut f: F) {
f();
f();
}
fn bir_kez<F: FnOnce() -> String>(f: F) -> String {
f()
}
fn main() {
let a = uygula(|x| x + 10, 5);
let mut n = 0;
iki_kez(|| n += 3);
let s = String::from("son");
let c = bir_kez(move || s);
println!("{} {} {}", a, n, c);
}Expected output
15 6 son
Questions and answers
Review the lesson questions together with their answers. To test yourself, solve the lesson interactively.
1 When taking a closure as a parameter, which bound is the most flexible (accepts the most closures)?
- FnOnce Correct answer
- Fn
- FnMut
- All equal
Explanation: Every closure is FnOnce. But if the function will call the closure more than once, it must ask for FnMut or Fn.
2 Bound for a mutating closure
fn iki_kez<F: ____()>(mut f: F) {
f();
f();
}
fn iki_kez<F: FnMut()>(mut f: F) {
f();
f();
}
Explanation: A closure called several times that may change state needs FnMut.
3 Closure and the narrowest trait it implements
| Term | Meaning |
|---|---|
|x| x + 10 |
Fn |
|| n += 3 |
FnMut |
move || s (returns a String) |
FnOnce |
|| println!("{x}") |
Fn (reads) |