🚧 Attention, peinture fraîche !
Cette page a été traduite par une seule personne et n'a pas été relue et vérifiée par quelqu'un d'autre ! Les informations peuvent par exemple être erronées, être formulées maladroitement, ou contenir d'autres types de fautes.
La récursivité
En interne, une fonction asynchrone génère une machine à états qui contient
chaque sous-future qui sont attendus avec await
. Cela rend la récursivité des
fonctions asynchrones un peu compliqué, car la machine à état doit se contenir
elle-même :
#![allow(unused)] fn main() { async fn etape_une() { /* ... */ } async fn etape_deux() { /* ... */ } struct EtapeUne; struct EtapeDeux; // Cette fonction ... async fn alpha() { etape_une().await; etape_deux().await; } // ... génère un type comme celui-ci : enum Alpha { Premiere(EtapeUne), Seconde(EtapeDeux), } // Donc cette fonction ... async fn recursif() { recursif().await; recursif().await; } // ... génère un type comme celui-ci : enum Recursif { Premiere(Recursif), Seconde(Recursif), } }
Cela ne fonctionne pas, nous avons créé un type de taille infinie ! Le compilateur va se plaindre :
error[E0733]: recursion in an `async fn` requires boxing
-- > src/lib.rs:1:22
|
1 | async fn recursif() {
| ^ an `async fn` cannot invoke itself directly
|
= note: a recursive `async fn` must be rewritten to return a boxed future.
Pour nous permettre cela, nous devons faire une dérivation en utilisant
Box
. Malheureusement, les limitations du compilateur font en sorte
qu'envelopper les appels à recursif()
dans une Box::pin
n'est pas
suffisant. Pour que cela fonctionne, nous devons transformer recursif
en
fonction synchrone pour retourner un bloc async
qui est dans une Box
:
#![allow(unused)] fn main() { use futures::future::{BoxFuture, FutureExt}; fn recursif() -> BoxFuture<'static, ()> { async move { recursif().await; recursif().await; }.boxed() } }