🚧 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.
Vous pouvez contribuer à l'amélioration de cette page sur sa Pull Request.
join!
La macro futures::join permet d'attendre que plusieurs futures différentes se
terminent pendant qu'elles sont toutes exécutées en concurrence.
join!
Lorsque nous avons besoin de faire plusieurs opérations asynchrones, il peut
être tentant d'utiliser .await en série sur elles :
async fn obtenir_livre_et_musique() -> (Livre, Musique) {
    let livre = obtenir_livre().await;
    let musique = obtenir_musique().await;
    (livre, musique)
}
En revanche, cela peut être plus lent que nécessaire, puisqu'il ne commence
qu'à obtenir_musique avant que obtenir_livre soit terminé. Dans d'autres
langages, les futures sont exécutées normalement jusqu'à leur fin, donc deux
opérations peuvent être exécutées en concurrence en appelant chacune des
async fn pour démarrer les futures, et ensuite attendre la fin des deux :
// MAUVAISE FAÇON -- ne faites pas cela
async fn obtenir_livre_et_musique() -> (Livre, Musique) {
    let future_livre = obtenir_livre();
    let future_musique = obtenir_musique();
    (future_livre.await, future_musique.await)
}
Malheureusement, les futures en Rust ne font rien tant qu'on n'utilise pas
.await sur elles. Cela signifie que les deux extraits de code ci-dessus vont
exécuter future_livre et future_musique en série au lieu de les exécuter en
concurrence. Pour exécuter correctement les deux futures en concurrence,
utilisons futures::join! :
use futures::join;
async fn obtenir_livre_et_musique() -> (Livre, Musique) {
    let future_livre = obtenir_livre();
    let future_musique = obtenir_musique();
    join!(future_livre, future_musique)
}
La valeur retournée par join! est une tuple contenant le résultat de chacune
des Futures qu'on lui a donné.
try_join!
Pour les futures qui retournent Result, il vaut mieux utiliser try_join!
plutôt que join!. Comme join! se termine uniquement lorsque toutes les
sous-futures se soient terminées, il va continuer à calculer les autres futures
même si une de ses sous-futures a retourné une Err.
Contrairement à join!, try_join! va se terminer tout de suite si une des
sous-futures retourne une erreur.
use futures::try_join;
async fn obtenir_livre() -> Result<Livre, String> { /* ... */ Ok(Livre) }
async fn obtenir_musique() -> Result<Musique, String> { /* ... */ Ok(Musique) }
async fn obtenir_livre_et_musique() -> Result<(Livre, Musique), String> {
    let future_livre = obtenir_livre();
    let future_musique = obtenir_musique();
    try_join!(future_livre, future_musique)
}
Notez que les futures envoyées au try_join! doivent toutes avoir le même type
d'erreur. Vous pouvez utiliser les fonctions .map_err(|e| ...) et
.err_into() de futures::future::TryFutureExt pour regrouper les types
d'erreurs :
use futures::{
    future::TryFutureExt,
    try_join,
};
async fn obtenir_livre() -> Result<Livre, ()> { /* ... */ Ok(Livre) }
async fn obtenir_musique() -> Result<Musique, String> { /* ... */ Ok(Musique) }
async fn obtenir_livre_et_musique() -> Result<(Livre, Musique), String> {
    let future_livre = obtenir_livre().map_err(|()| "Impossible d'obtenir le livre".to_string());
    let future_musique = obtenir_musique();
    try_join!(future_livre, future_musique)
}