🚧 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()
}
}