Когда в замыкании реализуются Fn, FnMut и FnOnce?

114

Каковы специфические условия для закрытия в целях осуществления Fn, FnMutи FnOnceчерты?

То есть:

  • Когда закрытие не реализует FnOnceчерту?
  • Когда закрытие не реализует FnMutчерту?
  • Когда закрытие не реализует Fnчерту?

Например, изменение состояния замыкания в его теле заставляет компилятор не реализовывать Fnего.

Денилсон Аморим
источник
11
Вы видели эту недавнюю замечательную статью о закрытии ?
Shepmaster

Ответы:

126

Каждая черта представляет все более и более ограничительные свойства замыканий / функций, обозначенных сигнатурами их call_...метода, и в частности типом self:

  • FnOnce( self) - это функции, которые можно вызвать один раз
  • FnMut( &mut self) - это функции, которые можно вызывать, если у них есть &mutдоступ к своей среде.
  • Fn( &self) - это функции, которые можно вызывать, если они имеют &доступ только к своей среде.

Закрытие |...| ...автоматически реализует столько из них, сколько может.

  • Все замыкания реализуются FnOnce: закрытие, которое нельзя вызвать один раз, не заслуживает названия. Обратите внимание: если замыкание реализуется только FnOnce, его можно вызвать только один раз.
  • Замыкания, которые не выходят за пределы своих захватов, реализуют FnMut, позволяя вызывать их более одного раза (если есть несанкционированный доступ к объекту функции).
  • Замыкания, которые не нуждаются в уникальном / изменяемом доступе к их захватам, реализуют Fn, что позволяет их вызывать практически везде.

Эти ограничения прямо вытекают из типа selfи «обессахаривания» замыканий в структуры; описано в моем сообщении в блоге Finding Closure in Rust .

Для получения информации о замыканиях см. Закрытие: анонимные функции, которые могут захватывать свое окружение на языке программирования Rust .

Юон
источник
Если замыкание реализуется только FnOnce, значит ли это, что его можно вызвать только один раз?
итого
@nalply, да, только один раз.
huon
9
Я неправильно прочитал комментарий nalply, и это вызвало у меня некоторое замешательство. Будущие читатели, обратите внимание, что он сказал «если закрытие только реализует FnOnce».
Sleeparrow
2
Подробности реализации: автоматически реализует как можно больше из них. не совсем верно, он будет реализовывать их автоматически, если кажется, что это необходимо. Вы можете обнаружить отсутствующий Fn-impl для замыкания, которое использовалось для аргумента FnMut, используя специализацию. Это ошибка github.com/rust-lang/rust/issues/26085
bluss 08