Quando um encerramento implementa Fn, FnMut e FnOnce?

114

Quais são as condições específicas para um fecho para implementar a Fn, FnMute FnOncetraços?

Isso é:

  • Quando um fechamento não implementa o FnOncetraço?
  • Quando um fechamento não implementa o FnMuttraço?
  • Quando um fechamento não implementa o Fntraço?

Por exemplo, alterar o estado do fechamento em seu corpo faz com que o compilador não implemente Fnnele.

Denilson Amorim
fonte
11
Você viu este excelente artigo recente sobre fechamentos ?
Shepmaster

Respostas:

126

Cada uma das características representa propriedades cada vez mais restritivas sobre fechamentos / funções, indicadas pelas assinaturas de seu call_...método e, particularmente, o tipo de self:

  • FnOnce( self) são funções que podem ser chamadas uma vez
  • FnMut( &mut self) são funções que podem ser chamadas se eles tiverem &mutacesso ao seu ambiente
  • Fn( &self) são funções que podem ser chamadas se eles só tiverem &acesso ao seu ambiente

Um fechamento |...| ...implementará automaticamente tantos deles quanto puder.

  • Todos os encerramentos implementam FnOnce: um encerramento que não pode ser chamado uma vez não merece o nome. Observe que, se uma closure implementa apenas FnOnce, ela pode ser chamada apenas uma vez.
  • Fechamentos que não saem de suas capturas são implementados FnMut, permitindo que sejam chamados mais de uma vez (se houver acesso sem alias ao objeto de função).
  • Fechamentos que não precisam de acesso exclusivo / mutável para implementar suas capturas Fn, permitindo que sejam chamados essencialmente em qualquer lugar.

Essas restrições decorrem diretamente do tipo selfe da "remoção" dos fechamentos em estruturas; descrito em minha postagem do blog Finding Closure in Rust .

Para obter informações sobre fechamentos, consulte Fechamentos: funções anônimas que podem capturar seu ambiente na linguagem de programação Rust .

Huon
fonte
Se um encerramento apenas implementa FnOnce, isso significa que ele pode ser chamado apenas uma vez?
basicamente
@atualmente, sim, apenas uma vez.
manhã
9
Eu interpretei mal o comentário de nalply e isso me causou alguma confusão. Futuros leitores, por favor, observem que ele disse "se um fechamento apenas implementa FnOnce".
sleeparrow de
2
Detalhe de implementação: implementará automaticamente o maior número possível. não for totalmente verdade, ele os implementará automaticamente se parecer necessário. Você pode detectar um Fn-impl ausente para um encerramento que foi usado para um argumento FnMut usando a especialização. Este é o bug github.com/rust-lang/rust/issues/26085
bluss