Gestion chaînée d'Option avec and_then()

RustRustBeginner
Pratiquer maintenant

This tutorial is from open-source community. Access the source code

💡 Ce tutoriel est traduit par l'IA à partir de la version anglaise. Pour voir la version originale, vous pouvez cliquer ici

Introduction

Dans ce laboratoire, le combinateur and_then() est présenté comme une alternative chaînable à map() lorsqu'on travaille avec Option<T>, car il évite d'imbriquer Option<Option<T>> et simplifie la lisibilité du code.

Note : Si le laboratoire ne spécifie pas de nom de fichier, vous pouvez utiliser n'importe quel nom de fichier que vous voulez. Par exemple, vous pouvez utiliser main.rs, le compiler et l'exécuter avec rustc main.rs &&./main.


Skills Graph

%%%%{init: {'theme':'neutral'}}%%%% flowchart RL rust(("Rust")) -.-> rust/BasicConceptsGroup(["Basic Concepts"]) rust(("Rust")) -.-> rust/FunctionsandClosuresGroup(["Functions and Closures"]) rust(("Rust")) -.-> rust/MemorySafetyandManagementGroup(["Memory Safety and Management"]) rust(("Rust")) -.-> rust/AdvancedTopicsGroup(["Advanced Topics"]) rust/BasicConceptsGroup -.-> rust/variable_declarations("Variable Declarations") rust/FunctionsandClosuresGroup -.-> rust/function_syntax("Function Syntax") rust/FunctionsandClosuresGroup -.-> rust/expressions_statements("Expressions and Statements") rust/MemorySafetyandManagementGroup -.-> rust/lifetime_specifiers("Lifetime Specifiers") rust/AdvancedTopicsGroup -.-> rust/operator_overloading("Traits for Operator Overloading") subgraph Lab Skills rust/variable_declarations -.-> lab-99237{{"Gestion chaînée d'Option avec and_then()"}} rust/function_syntax -.-> lab-99237{{"Gestion chaînée d'Option avec and_then()"}} rust/expressions_statements -.-> lab-99237{{"Gestion chaînée d'Option avec and_then()"}} rust/lifetime_specifiers -.-> lab-99237{{"Gestion chaînée d'Option avec and_then()"}} rust/operator_overloading -.-> lab-99237{{"Gestion chaînée d'Option avec and_then()"}} end

Combinateurs : and_then

map() a été décrit comme un moyen chaînable de simplifier les instructions match. Cependant, utiliser map() sur une fonction qui renvoie un Option<T> conduit à l'imbrication Option<Option<T>>. Enchaîner plusieurs appels peut alors devenir confus. C'est là que vient un autre combinateur appelé and_then(), connu dans certains langages sous le nom de flatmap.

and_then() appelle sa fonction d'entrée avec la valeur encapsulée et renvoie le résultat. Si l'Option est None, alors elle renvoie None à la place.

Dans l'exemple suivant, cookable_v3() renvoie un Option<Food>. Utiliser map() au lieu de and_then() aurait donné un Option<Option<Food>>, qui est un type invalide pour eat().

#![allow(dead_code)]

#[derive(Debug)] enum Food { CordonBleu, Steak, Sushi }
#[derive(Debug)] enum Day { Monday, Tuesday, Wednesday }

// Nous n'avons pas les ingrédients pour faire du Sushi.
fn have_ingredients(food: Food) -> Option<Food> {
    match food {
        Food::Sushi => None,
        _           => Some(food),
    }
}

// Nous avons la recette pour tout, sauf le Cordon Bleu.
fn have_recipe(food: Food) -> Option<Food> {
    match food {
        Food::CordonBleu => None,
        _                => Some(food),
    }
}

// Pour préparer un plat, nous avons besoin à la fois de la recette et des ingrédients.
// Nous pouvons représenter la logique avec une chaîne d'`match` :
fn cookable_v1(food: Food) -> Option<Food> {
    match have_recipe(food) {
        None       => None,
        Some(food) => have_ingredients(food),
    }
}

// Cela peut être commodément réécrit de manière plus compacte avec `and_then()` :
fn cookable_v3(food: Food) -> Option<Food> {
    have_recipe(food).and_then(have_ingredients)
}

// Sinon, nous devrions `flatten()` un `Option<Option<Food>>`
// pour obtenir un `Option<Food>` :
fn cookable_v2(food: Food) -> Option<Food> {
    have_recipe(food).map(have_ingredients).flatten()
}

fn eat(food: Food, day: Day) {
    match cookable_v3(food) {
        Some(food) => println!("Yay! On {:?} we get to eat {:?}.", day, food),
        None       => println!("Oh no. We don't get to eat on {:?}?", day),
    }
}

fn main() {
    let (cordon_bleu, steak, sushi) = (Food::CordonBleu, Food::Steak, Food::Sushi);

    eat(cordon_bleu, Day::Monday);
    eat(steak, Day::Tuesday);
    eat(sushi, Day::Wednesday);
}

Sommaire

Félicitations ! Vous avez terminé le laboratoire Combinateurs : And_then. Vous pouvez pratiquer d'autres laboratoires sur LabEx pour améliorer vos compétences.