Autres utilisations de?

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, il est expliqué que l'opérateur ? en Rust peut être utilisé pour convertir automatiquement les erreurs dans le type de retour souhaité, éliminant ainsi la nécessité de traiter explicitement les erreurs avec map_err.

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/FunctionsandClosuresGroup(["Functions and Closures"]) rust(("Rust")) -.-> rust/BasicConceptsGroup(["Basic Concepts"]) rust(("Rust")) -.-> rust/DataTypesGroup(["Data Types"]) rust(("Rust")) -.-> rust/DataStructuresandEnumsGroup(["Data Structures and Enums"]) rust(("Rust")) -.-> rust/AdvancedTopicsGroup(["Advanced Topics"]) rust/BasicConceptsGroup -.-> rust/variable_declarations("Variable Declarations") rust/DataTypesGroup -.-> rust/integer_types("Integer Types") rust/DataTypesGroup -.-> rust/string_type("String Type") rust/DataTypesGroup -.-> rust/type_casting("Type Conversion and Casting") rust/FunctionsandClosuresGroup -.-> rust/function_syntax("Function Syntax") rust/FunctionsandClosuresGroup -.-> rust/expressions_statements("Expressions and Statements") rust/DataStructuresandEnumsGroup -.-> rust/method_syntax("Method Syntax") rust/AdvancedTopicsGroup -.-> rust/traits("Traits") rust/AdvancedTopicsGroup -.-> rust/operator_overloading("Traits for Operator Overloading") subgraph Lab Skills rust/variable_declarations -.-> lab-99249{{"Autres utilisations de?"}} rust/integer_types -.-> lab-99249{{"Autres utilisations de?"}} rust/string_type -.-> lab-99249{{"Autres utilisations de?"}} rust/type_casting -.-> lab-99249{{"Autres utilisations de?"}} rust/function_syntax -.-> lab-99249{{"Autres utilisations de?"}} rust/expressions_statements -.-> lab-99249{{"Autres utilisations de?"}} rust/method_syntax -.-> lab-99249{{"Autres utilisations de?"}} rust/traits -.-> lab-99249{{"Autres utilisations de?"}} rust/operator_overloading -.-> lab-99249{{"Autres utilisations de?"}} end

Autres utilisations de ?

Remarquez dans l'exemple précédent que notre première réaction à l'appel de parse est de map l'erreur d'une erreur de bibliothèque en une erreur encadrée :

.and_then(|s| s.parse::<i32>())
 .map_err(|e| e.into())

Puisque c'est une opération simple et courante, il serait pratique de pouvoir l'omettre. Malheureusement, car and_then n'est pas suffisamment flexible, on ne peut pas. Cependant, on peut au lieu utiliser ?.

? a été précédemment expliqué comme étant soit unwrap soit return Err(err). C'est seulement en partie vrai. En réalité, cela signifie unwrap ou return Err(From::from(err)). Puisque From::from est une utilité de conversion entre différents types, cela signifie que si vous utilisez ? où l'erreur est convertible en type de retour, elle sera automatiquement convertie.

Ici, on réécrit l'exemple précédent en utilisant ?. En conséquence, le map_err disparaîtra lorsque From::from est implémenté pour notre type d'erreur :

use std::error;
use std::fmt;

// Changez l'alias en `Box<dyn error::Error>`.
type Result<T> = std::result::Result<T, Box<dyn error::Error>>;

#[derive(Debug)]
struct EmptyVec;

impl fmt::Display for EmptyVec {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "invalid first item to double")
    }
}

impl error::Error for EmptyVec {}

// La même structure que précédemment mais plutôt que de chaîner tous les `Results`
// et les `Options` ensemble, on utilise `?` pour extraire immédiatement la valeur interne.
fn double_first(vec: Vec<&str>) -> Result<i32> {
    let first = vec.first().ok_or(EmptyVec)?;
    let parsed = first.parse::<i32>()?;
    Ok(2 * parsed)
}

fn print(result: Result<i32>) {
    match result {
        Ok(n)  => println!("The first doubled is {}", n),
        Err(e) => println!("Error: {}", e),
    }
}

fn main() {
    let numbers = vec!["42", "93", "18"];
    let empty = vec![];
    let strings = vec!["tofu", "93", "18"];

    print(double_first(numbers));
    print(double_first(empty));
    print(double_first(strings));
}

Cela est maintenant en fait assez propre. Comparé au panic d'origine, il est très similaire à remplacer les appels unwrap par ? sauf que les types de retour sont Result. En conséquence, ils doivent être déstructurés au niveau supérieur.

Sommaire

Félicitations ! Vous avez terminé le laboratoire Autres utilisations de ?. Vous pouvez pratiquer d'autres laboratoires sur LabEx pour améliorer vos compétences.