Я бы подумал, что добавление move
в начало замыкания приведет к тому же результату: ...
Это отчасти делает то же самое.Вы просто забыли объявить name
и welcome
как изменяемые.Этот код работает нормально:
fn main() {
let mut name = String::from("Alice");
let mut welcome = move || {
name += " and Bob";
println!("Welcome, {}", name);
};
welcome();
}
Обе версии замыкания приводят к перемещению name
в замыкание.В первой версии это неявно вызвано потреблением name
внутри замыкания.Вторая версия не использует name
, но использует ключевое слово move
для принудительного перемещения.
… и приводит к перемещению значения и созданию FnOnce
.
Перемещение значения в замыкание не делает его FnOnce
.Если замыкание потребляет захваченного значения, оно становится FnOnce
, поскольку оно может сделать это только один раз.Таким образом, первая версия замыкания - FnOnce
, поскольку она потребляет name
.Выше приведено значение FnMut
, и его можно вызывать несколько раз.Двойной вызов приводит к выводу
Welcome, Alice and Bob
Welcome, Alice and Bob and Bob
(я использовал несколько небрежных имен признаков функций. Фактически, каждое замыкание реализует FnOnce
, так как каждое замыкание может быть вызвано вхотя бы один раз. Некоторые замыкания могут вызываться несколько раз, поэтому они дополнительно FnMut
. А некоторые замыкания, которые можно вызывать несколько раз, не изменяют свое захваченное состояние, поэтому они равны Fn
в дополнение к двум другим характеристикам.)