Pin
- O tipo
Pin e o conceito de pinning são componentes fundamentais do ecossistema assíncrono de Rust
- No entanto,
Pin é um dos elementos mais difíceis de abordar e mais fáceis de interpretar errado
- Este artigo explica o que
Pin busca alcançar, como ele surgiu e quais são os problemas atuais de Pin
Requirements
- Para dar suporte a referências em funções assíncronas, era necessário armazenar referências dentro de
Future
- O problema é que essas referências podem ser autoreferenciais
- Código de exemplo:
async fn foo<'a>(z: &'a mut i32) { ... }
async fn bar(x: i32, y: i32) -> i32 {
let mut z = x + y;
foo(&mut z).await;
z
}
- O estado interno de
Bar é o seguinte:
enum Bar {
Start { x: i32, y: i32 },
FirstAwait { z: i32, foo: Foo<'?> },
Complete,
}
- O objetivo de
Pin é manipular tipos autoreferenciais com segurança
Non-solutions: move constructors and offset pointers
- Construtores de movimento e ponteiros com deslocamento não funcionam em Rust
- Construtores de movimento ajustam ponteiros durante a movimentação, mas isso não é possível em Rust
- Ponteiros com deslocamento não funcionam porque, em tempo de compilação, não é possível saber se uma referência é autoreferencial ou não
The “pinned typestate”
- Um objeto não precisa ser imóvel sempre, mas precisa se tornar imóvel a partir de um determinado momento
- No modelo de Ralf Jung, o objeto faz a transição do estado "possuído" para o estado "compartilhado" e depois para o estado "fixado"
- Ao entrar no estado fixado, o objeto não pode mais ser movido
?Move
- Antes de
Pin, foi tentada uma solução baseada em um novo trait chamado Move
- Tipos que não implementam
Move passam para o estado fixado quando uma referência é obtida
- Porém,
Move não oferece compatibilidade retroativa
Pin
Pin projetou um novo tipo de referência para colocar objetos no estado fixado
Pin foi implementado como uma API de biblioteca para manter a compatibilidade retroativa
- Foi adicionado o auto trait
Unpin para que a maioria dos tipos não precise distinguir entre o estado fixado e o estado normal
The problems with Pin
Pin tem vários problemas de usabilidade
Pin foi implementado como um tipo de biblioteca, e por isso muitas funcionalidades dos tipos normais de referência se perdem
- Por exemplo,
&mut T não implementa Copy, mas pode ser passado como argumento várias vezes
Pin não oferece essa conveniência
- Muito da confusão surge ao usar
Pin
In my next post…
Pin permite compilar com segurança referências arbitrárias em funções assíncronas
- No entanto,
Pin aumenta a complexidade, e o próximo artigo tratará de formas de melhorar isso
Resumo do GN⁺
Pin é um componente importante do ecossistema assíncrono de Rust
- Os problemas de usabilidade de
Pin decorrem do fato de ele ter sido implementado como um tipo de biblioteca
- O próximo artigo abordará maneiras de melhorar
Pin
- Um projeto com funcionalidade semelhante é
pin-project-lite
1 comentários
Comentários no Hacker News
O motivo de
Pinser difícil de entender é que a documentação oficial não o explica com clarezaPingarante que um objeto nunca será movido", mas isso não é verdadeUnpin,Pinnormalmente não faz nadaTpara os quaisPinrealmente funciona é muito peculiar, e isso não é suficientemente enfatizado na documentaçãoPiné difícil porque não tem significado por si sóPin, nem a linguagem nem a biblioteca padrão dizem o quePinpode ou não pode fazerInnerTypecria métodos e APIs adicionais (internamente inseguros) para permitir a manipulação de objetos fixadosPinem si é fornecer um ponteiro com menos "funcionalidades intrínsecas"Deveriam adicionar "rust" ao título para ficar claro sobre o que é o artigo
O termo "value identity" não é definido em nenhum lugar da documentação do Mojo
Piné um bom exemplo de um nome tecnicamente correto, mas difícil de entenderDroptem um significado mais familiar, mas "pinning" nãoimmovable!(…)talvez fosse melhor, mas é difícil pensar em um nome melhorprevent_moving!(…)e um traitPreventMovepoderiam ser melhoresEm uma linguagem parecida com Rust que tivesse move-constructors, a necessidade de
Pinpoderia desaparecerÉ possível mover objetos via
mem::swap/replacepor meio de uma referência&mut, mas isso raramente é realmente necessárioswapereplaceinseguros poderia resolver o problemaWithoutBoats está promovendo uma discussão ativa sobre os temas iteradores assíncronos,
pollepinPinning/!Moveé útil para muitos usos além de async/await