Travado na sintaxe async/await do Rust, algum recurso?

JA James_1984 IE 🛠️ Especialista 👁 87 ⚑ Denunciar Programação

Estou tentando aprender Rust há um mês e fico batendo a cabeça com async/await. Toda vez que tento escrever uma função async que chama outra função async, recebo esses erros de lifetime confusos. Tem algum tutorial ou padrão bom que explique isso em português simples em vez de mensagens de erro do compilador?

4 respostas

★ Melhor resposta
Wolf DE 🛠️ Especialista 💬 89 respostas ⚑

Os erros de lifetime na verdade não são o problema real - são sintomas de algo mais simples. Antes de entrar em parafuso com o borrow checker, tenta isso: escreve suas funções async com tipos de retorno explícitos `Box<dyn Future<Output = YourType>>` em vez da sintaxe `impl Future`, pelo menos enquanto tá aprendendo. Isso força você a ver exatamente o que tá sendo capturado e deixa o compilador menos críptico sobre o que tá realmente falhando. Quando conseguir uma versão funcionando desse jeito, você consegue refatorar de volta para `impl Future` e entender *por que* o compilador agora aceita, em vez de ficar mexendo até os erros pararem.

Você está usando `.await` nos pontos de chamada, ou está só chamando a função async sem fazer await dela? Os erros de lifetime geralmente se resumem ao compilador vendo uma referência emprestada que vive menos tempo do que o future precisa - o que é diferente de async ser mágica, é só o borrow checker do Rust fazendo seu trabalho através dos pontos de await. O livro oficial Async Rust (no site do Rust) tem uma seção que explica exatamente isso, e é genuinamente mais claro do que a maioria dos tutoriais. Se você está caçando mensagens de erro específicas, tente isolar um exemplo pequeno que falha, poste no r/rust ou no fórum do Rust - as pessoas lá são pacientes em explicar o problema de verdade ao invés do ruído do erro.

James_1984 asker Sim, estou usando `.await` nos locais onde faço as chamadas. O borrow checker através dos pontos de await faz sentido - vou verificar aquela seção do livro Async Rust.
Susan CA 🛠️ Especialista 💬 98 respostas ⚑

pare de tentar lutar contra o borrow checker e em vez disso pense em async/await como criando uma state machine - cada await é basicamente uma pausa onde rust precisa saber que dados sobrevivem até a próxima pausa. é por isso que você está recebendo erros de lifetime. o compilador não está sendo obtuso, ele genuinamente não sabe se seus dados emprestados ainda vão ser válidos quando a execução retomar.

o rust async book oficial (rust-lang.org/what/wasm/book) é bem sólido para isso, mas o que me ajudou mais foi ler o tutorial do tokio porque usa exemplos reais em vez de teoria abstrata. a série de vídeos de Jon Gjengset no youtube sobre async rust faz sentido para muita gente também - ele passa pelo modelo mental passo a passo em vez de jogar sintaxe em você. um padrão que desmistificou as coisas pra mim: quando você tá encadeando chamadas async, confie em `tokio::spawn` ou use `.await` chains consistentemente pra não estar misturando referências emprestadas com async boundaries.

uma coisa prática pra tentar - escreva que dados sua função async realmente precisa manter ao redor entre awaits, aí passa só aquilo explicitamente. não passa referências se você consegue passar valores owned. sim, às vezes sente como desperdício mas força você a entender o lifetime issue em vez de ficar brigando com mensagens de erro. e mexe no playground (play.rust-lang.org) com exemplos minúsculos antes de tackling código de verdade - às vezes um caso de teste de 5 linhas revela o que tá acontecendo de verdade mais rápido que debugar seu projeto principal.

A coisa que finalmente fez sentido pra mim foi perceber que funções async na verdade não retornam o que você vê na assinatura - elas retornam uma Future que *eventualmente* vai produzir aquele valor, e o borrow checker precisa saber que toda referência que você tá segurando ainda vai ser válida quando essa Future realmente rodar. Passei semanas lutando contra erros de lifetime em chamadas async aninhadas até começar a escrever qual dado cada ponto de `.await` dependia, quase como se tivesse narrando o ciclo de vida da Future em voz alta. Tenta o tutorial do Tokio e especialmente a seção deles sobre spawning de tasks - ver exemplos concretos do que é movido pra uma task criada versus o que é emprestado entre pontos de await ajudou muito mais do que explicações abstratas. O capítulo async do Rust book também melhorou bastante, então não pula nem mesmo se já tiver lido partes do livro principal.

Sua resposta

Entrarpara responder.