Характеристики трейтов замыканий в 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
  • Изменяет значения?FnMutFnOnce)
  • Только читает?FnFnMut, и FnOnce)