Характеристики трейтов замыканий в Rust
FnOnce
- Гарантии: Можно вызвать хотя бы один раз
- Захват значений: Может перемещать захваченные значения из своего тела
- Модификация: Может потреблять захваченные значения
- Использование: Только однократный вызов
- Пример:
#![allow(unused)] fn main() { let s = String::from("hello"); let closure = move || { println!("{}", s); // s перемещается в замыкание drop(s); // значение потребляется }; closure(); // можно вызвать только один раз // closure(); // ошибка! второй вызов невозможен }
FnMut
- Гарантии: Можно вызвать многократно
- Захват значений: Не перемещает значения, но может изменять захваченные значения
- Модификация: Требует
&mut selfдля вызова - Использование: Многократный вызов с возможностью мутации
- Пример:
#![allow(unused)] fn main() { let mut count = 0; let mut closure = || { count += 1; // изменяет захваченное значение println!("Count: {}", count); }; closure(); // Count: 1 closure(); // Count: 2 - можно вызывать многократно }
Fn
- Гарантии: Можно вызвать многократно без побочных эффектов
- Захват значений: Не перемещает и не изменяет захваченные значения (или ничего не захватывает)
- Модификация: Требует
&selfдля вызова - Использование: Многократный вызов, безопасность для многопоточности
- Пример:
#![allow(unused)] fn main() { let x = 10; let closure = || { println!("x = {}", x); // только чтение, без изменений }; closure(); // x = 10 closure(); // x = 10 - можно вызывать многократно }
Иерархия реализации:
FnOnce (базовый)
↑
FnMut
↑
Fn (наиболее ограничивающий)
Правило: Если замыкание реализует Fn, оно автоматически реализует FnMut и FnOnce. Если реализует FnMut, то автоматически реализует FnOnce.
Определение по использованию:
- Перемещает значения? → Только
FnOnce - Изменяет значения? →
FnMut(иFnOnce) - Только читает? →
Fn(иFnMut, иFnOnce)