Encapsulation d'erreurs avec un type personnalisé

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, l'approche alternative consistant à encapsuler les erreurs dans un type d'erreur personnalisé est démontrée. L'exemple de code montre comment définir un alias de type Result qui utilise l'énumération DoubleError comme variant d'erreur, qui encapsule l'ParseIntError de la bibliothèque standard. En implémentant les traits fmt::Display, error::Error et From, le type d'erreur personnalisé peut fournir des informations supplémentaires et gérer les erreurs sous-jacentes.

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/DataTypesGroup(["Data Types"]) rust(("Rust")) -.-> rust/FunctionsandClosuresGroup(["Functions and Closures"]) rust(("Rust")) -.-> rust/AdvancedTopicsGroup(["Advanced Topics"]) rust(("Rust")) -.-> rust/DataStructuresandEnumsGroup(["Data Structures and Enums"]) 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-99250{{"Encapsulation d'erreurs avec un type personnalisé"}} rust/integer_types -.-> lab-99250{{"Encapsulation d'erreurs avec un type personnalisé"}} rust/string_type -.-> lab-99250{{"Encapsulation d'erreurs avec un type personnalisé"}} rust/type_casting -.-> lab-99250{{"Encapsulation d'erreurs avec un type personnalisé"}} rust/function_syntax -.-> lab-99250{{"Encapsulation d'erreurs avec un type personnalisé"}} rust/expressions_statements -.-> lab-99250{{"Encapsulation d'erreurs avec un type personnalisé"}} rust/method_syntax -.-> lab-99250{{"Encapsulation d'erreurs avec un type personnalisé"}} rust/traits -.-> lab-99250{{"Encapsulation d'erreurs avec un type personnalisé"}} rust/operator_overloading -.-> lab-99250{{"Encapsulation d'erreurs avec un type personnalisé"}} end

Encapsulation des erreurs

Une alternative au conditionnement des erreurs consiste à les encapsuler dans votre propre type d'erreur.

use std::error;
use std::error::Error;
use std::num::ParseIntError;
use std::fmt;

type Result<T> = std::result::Result<T, DoubleError>;

#[derive(Debug)]
enum DoubleError {
    EmptyVec,
    // Nous différons l'implémentation de l'erreur d'analyse pour leur erreur.
    // Fournir des informations supplémentaires nécessite d'ajouter plus de données au type.
    Parse(ParseIntError),
}

impl fmt::Display for DoubleError {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        match *self {
            DoubleError::EmptyVec =>
                write!(f, "veuillez utiliser un vecteur avec au moins un élément"),
            // L'erreur encapsulée contient des informations supplémentaires et est disponible
            // via la méthode source().
            DoubleError::Parse(..) =>
                write!(f, "la chaîne de caractères fournie ne peut pas être analysée comme un entier"),
        }
    }
}

impl error::Error for DoubleError {
    fn source(&self) -> Option<&(dyn error::Error + 'static)> {
        match *self {
            DoubleError::EmptyVec => None,
            // La cause est le type d'erreur d'implémentation sous-jacent. Est implicitement
            // cast en objet de trait `&error::Error`. Cela fonctionne car le
            // type sous-jacent implémente déjà le trait `Error`.
            DoubleError::Parse(ref e) => Some(e),
        }
    }
}

// Implémentez la conversion de `ParseIntError` en `DoubleError`.
// Cela sera automatiquement appelé par `?` si un `ParseIntError`
// doit être converti en un `DoubleError`.
impl From<ParseIntError> for DoubleError {
    fn from(err: ParseIntError) -> DoubleError {
        DoubleError::Parse(err)
    }
}

fn double_first(vec: Vec<&str>) -> Result<i32> {
    let first = vec.first().ok_or(DoubleError::EmptyVec)?;
    // Ici, nous utilisons implicitement l'implémentation de `From` de `ParseIntError` (que
    // nous avons définie ci-dessus) pour créer un `DoubleError`.
    let parsed = first.parse::<i32>()?;

    Ok(2 * parsed)
}

fn print(result: Result<i32>) {
    match result {
        Ok(n)  => println!("Le premier doublé est {}", n),
        Err(e) => {
            println!("Erreur : {}", e);
            if let Some(source) = e.source() {
                println!("  Causée par : {}", source);
            }
        },
    }
}

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 ajoute un peu plus de code de base pour gérer les erreurs et peut ne pas être nécessaire dans toutes les applications. Il existe certaines bibliothèques qui peuvent prendre en charge le code de base pour vous.

Sommaire

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