¿Cuándo implementa un cierre Fn, FnMut y FnOnce?

114

¿Cuáles son las condiciones específicas para un cierre que ejecute el Fn, FnMuty FnOncerasgos?

Es decir:

  • ¿Cuándo un cierre no implementa el FnOncerasgo?
  • ¿Cuándo un cierre no implementa el FnMutrasgo?
  • ¿Cuándo un cierre no implementa el Fnrasgo?

Por ejemplo, mutar el estado del cierre en su cuerpo hace que el compilador no implemente Fnen él.

Denilson Amorim
fuente
11
¿Has visto este gran artículo reciente sobre cierres ?
Shepmaster

Respuestas:

126

Cada uno de los rasgos representa propiedades cada vez más restrictivas sobre cierres / funciones, indicadas por las firmas de su call_...método, y particularmente el tipo de self:

  • FnOnce( self) son funciones que se pueden llamar una vez
  • FnMut( &mut self) son funciones que se pueden llamar si tienen &mutacceso a su entorno
  • Fn( &self) son funciones que se pueden llamar si solo tienen &acceso a su entorno

Un cierre |...| ...implementará automáticamente tantos como sea posible.

  • Todos los cierres se implementan FnOnce: un cierre que no se puede llamar una vez no merece el nombre. Tenga en cuenta que si un cierre solo se implementa FnOnce, solo se puede llamar una vez.
  • Los cierres que no se mueven fuera de sus capturas se implementan FnMut, lo que les permite ser llamados más de una vez (si hay acceso sin alias al objeto de función).
  • Los cierres que no necesitan acceso único / mutable a sus capturas se implementan Fn, lo que les permite ser llamados esencialmente en todas partes.

Estas restricciones se derivan directamente del tipo selfy del "desugaring" de los cierres en estructuras; descrito en la publicación de mi blog Finding Closure in Rust .

Para obtener información sobre cierres, consulte Cierres: funciones anónimas que pueden capturar su entorno en el lenguaje de programación Rust .

huon
fuente
Si un cierre solo se implementa FnOnce, ¿significa esto que solo se puede llamar una vez?
finalmente
@nalply, sí, solo una vez.
huon
9
Leí mal el comentario de nalply y me causó cierta confusión. Futuros lectores, tenga en cuenta que dijo "si un cierre sólo se implementa FnOnce".
Sleeparrow
2
Detalle de implementación: implementará automáticamente tantos como pueda. no es del todo cierto, los implementará automáticamente si parece ser necesario. Puede detectar una Fn-impl faltante para un cierre que se usó para un argumento FnMut usando la especialización. Este es el error github.com/rust-lang/rust/issues/26085
rubor