Ho problemi con la sintassi di Rust async/await, avete risorse?

JA James_1984 IE 🛠️ Specialista 👁 92 ⚑ Segnala Programmazione

Sto cercando di imparare Rust da un mese e continuo a sbattere la testa contro async/await. Ogni volta che provo a scrivere una funzione async che chiama un'altra funzione async, mi ritrovo con questi errori di lifetime confusionari. Ci sono tutorial o pattern decenti che spieghino davvero questa roba in modo comprensibile, invece di buttarti in faccia i messaggi di errore del compilatore?

4 risposte

★ Miglior risposta
Wolf DE 🛠️ Specialista 💬 89 risposte ⚑

Gli errori di lifetime non sono in realtà il muro contro cui stai sbattendo - sono sintomi di qualcosa di più semplice. Prima di sprofondare nel borrow checker, prova questo: scrivi le tue funzioni async con tipi di ritorno espliciti `Box<dyn Future<Output = YourType>>` invece della sintassi `impl Future`, almeno mentre stai imparando. Ti costringe a vedere esattamente cosa viene catturato e rende il compilatore meno criptico su cosa sta effettivamente fallendo. Una volta che hai una versione funzionante in questo modo, puoi fare un refactor tornando a `impl Future` e capire *perché* il compilatore ora l'accetta, invece di semplicemente modificare le cose finché gli errori non scompaiono.

Stai usando `.await` nei siti di chiamata, oppure stai solo chiamando la funzione async senza aspettarla? Gli errori di lifetime spesso si riducono al compilatore che vede un riferimento borrowato che vive meno a lungo di quanto il future ne abbia bisogno - il che è diverso dal fatto che async sia magia, è solo il borrow checker di Rust che fa il suo lavoro attraverso i punti di await. Il libro ufficiale Async Rust (sul sito di Rust) ha una sezione che spiega esattamente questo, ed è genuinamente più chiaro della maggior parte dei tutorial. Se stai cercando messaggi di errore specifici, prova a isolare un piccolo esempio che fallisce, postalo su r/rust o sul forum di Rust - lì la gente è paziente nel spiegare il problema vero piuttosto che il rumore degli errori.

James_1984 asker Sì, sto usando `.await` nei siti di chiamata. Il borrow checker attraverso i punti di await ha senso - controllerò quella sezione dell'Async Rust book.
Susan CA 🛠️ Specialista 💬 98 risposte ⚑

smetti di combattere il borrow checker e invece pensa a async/await come alla creazione di una state machine - ogni await point è fondamentalmente una pausa dove Rust ha bisogno di sapere quali dati sopravvivono fino alla prossima pausa. ecco perché ricevi errori di lifetime. il compilatore non sta facendo il difficile, genuinamente non sa se i tuoi dati borrowed saranno ancora validi quando l'esecuzione riprenderà.

l'async book ufficiale di Rust (rust-lang.org/what/wasm/book) è abbastanza solido per questo, ma quello che mi ha aiutato di più è stato leggere il tutorial di Tokio perché usa esempi reali invece di teoria astratta. la serie video di Jon Gjengset su YouTube riguardo async Rust fa scattare la lampadina a molti - cammina attraverso il modello mentale passo dopo passo invece di dumparti addosso la sintassi. un pattern che ha smistificato le cose per me: quando stai concatenando chiamate async, affidati a `tokio::spawn` o usa catene `.await` in modo coerente così non stai mischiando referenced borrowate con confini async.

una cosa pratica da provare - scrivi quale dato la tua funzione async effettivamente ha bisogno di tenere in giro attraverso gli await, poi passa solo quello esplicitamente. non passare reference se puoi passare valori owned. sì, a volte sembra uno spreco ma ti forza a capire il problema di lifetime invece di combattere i messaggi d'errore. inoltre gioca nel playground (play.rust-lang.org) con piccoli esempi prima di affrontare il codice vero - a volte un test case di 5 righe rivela cosa sta andando davvero storto più velocemente che debuggare il tuo progetto principale.

La cosa che finalmente mi ha fatto scattare la lampadina è stata capire che le funzioni async non restituiscono quello che vedi nella firma - restituiscono un Future che *eventualmente* produrrà quel valore, e il borrow checker ha bisogno di sapere che ogni reference che stai mantenendo sarà ancora valida quando quel Future si eseguirà effettivamente. Ho passato settimane a lottare contro errori di lifetime nelle chiamate async annidate finché non ho iniziato a scrivere su quali dati ogni punto `.await` dipendesse, quasi come se stessi narrando il ciclo di vita del Future ad alta voce. Prova il tutorial di Tokio e soprattutto la loro sezione su come spawning dei task - vedere esempi concreti di cosa viene spostato in un task spawned rispetto a cosa viene preso in prestito tra i punti await ha aiutato molto di più delle spiegazioni astratte. Anche il capitolo async del Rust book è migliorato, quindi non saltarlo nemmeno se hai già letto parti del libro principale.

La tua risposta

Accediper rispondere.