Трейт FnMut
Трейт FnMut - это один из трёх трейтов для вызываемых объектов
в Rust, наряду с Fn и FnOnce. Он описывает
функции и замыкания, которые могут быть вызваны несколько раз
и при этом изменяют захваченные переменные окружения.
В отличие от трейта Fn, который допускает только
неизменяемый доступ к захваченному состоянию, FnMut
позволяет изменять это состояние. Параметром трейт принимает
набор типов аргументов и возвращаемый тип через ассоциированный
тип Output.
Замыкания автоматически реализуют FnMut, если они
изменяют захваченные переменные. Любой тип, реализующий
FnMut, также реализует FnOnce, но не обязательно
реализует Fn.
Синтаксис
trait FnMut<Args>: FnOnce<Args>
{
extern "rust-call" fn call_mut(&mut self, args: Args) -> Self::Output;
}
На практике напрямую трейт FnMut почти никогда
не реализуют вручную - компилятор генерирует реализацию
автоматически для замыканий. В сигнатурах функций трейт
используют как ограничение вида F: FnMut(A) -> B
или impl FnMut(A) -> B.
Пример
Давайте создадим замыкание, которое изменяет захваченную
переменную counter, и вызовем его несколько раз:
fn main()
{
let mut counter = 0;
let mut increment = || {
counter += 1;
println!("{}", counter);
};
increment();
increment();
increment();
}
Результат выполнения кода:
1
2
3
Пример
Давайте напишем функцию, которая принимает замыкание
с ограничением FnMut и применяет его к каждому
элементу вектора:
fn apply_all<F>(items: &mut Vec<i32>, mut f: F)
where
F: FnMut(i32) -> i32,
{
for item in items.iter_mut()
{
*item = f(*item);
}
}
fn main()
{
let mut numbers = vec![1, 2, 3, 4, 5];
let mut factor = 1;
apply_all(&mut numbers, |x| {
factor += 1;
x * factor
});
println!("{:?}", numbers);
}
Результат выполнения кода:
[2, 6, 12, 20, 30]
Замыкание изменяет переменную factor при каждом
вызове, поэтому каждый элемент умножается на своё
уникальное значение.
Пример
Давайте сохраним замыкание в переменной с типом
Box<dyn FnMut()> и вызовем его через этот трейт-объект:
fn main()
{
let mut total = 0;
let mut acc: Box<dyn FnMut(i32)> = Box::new(|x| {
total += x;
println!("total = {}", total);
});
acc(10);
acc(20);
acc(30);
}
Результат выполнения кода:
total = 10
total = 30
total = 60
Смотрите также
-
трейт
Fn,
который описывает замыкания без изменения захваченного состояния -
трейт
FnOnce,
который описывает замыкания, вызываемые только один раз -
трейт
dyn Trait,
который позволяет создавать трейт-объекты для динамического вызова -
трейт
Trait Bound,
который задаёт ограничения на обобщённые типы