Explorer les types associés de Rust

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, nous explorons le concept de types associés en Rust, qui permet d'améliorer la lisibilité du code en définissant des types internes localement dans un trait en tant que types de sortie. Cela est réalisé en utilisant le mot clé type à l'intérieur de la définition du trait. Avec les types associés, les fonctions qui utilisent le trait n'ont plus besoin d'exprimer explicitement les types A et B, rendant le code plus concis et flexible. Nous réécrivons un exemple d'une section précédente en utilisant des types associés pour illustrer leur utilisation en pratique.

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/DataStructuresandEnumsGroup(["Data Structures and Enums"]) rust(("Rust")) -.-> rust/AdvancedTopicsGroup(["Advanced Topics"]) rust(("Rust")) -.-> rust/BasicConceptsGroup(["Basic Concepts"]) rust(("Rust")) -.-> rust/DataTypesGroup(["Data Types"]) rust/BasicConceptsGroup -.-> rust/variable_declarations("Variable Declarations") rust/DataTypesGroup -.-> rust/integer_types("Integer Types") 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-99354{{"Explorer les types associés de Rust"}} rust/integer_types -.-> lab-99354{{"Explorer les types associés de Rust"}} rust/type_casting -.-> lab-99354{{"Explorer les types associés de Rust"}} rust/function_syntax -.-> lab-99354{{"Explorer les types associés de Rust"}} rust/expressions_statements -.-> lab-99354{{"Explorer les types associés de Rust"}} rust/method_syntax -.-> lab-99354{{"Explorer les types associés de Rust"}} rust/traits -.-> lab-99354{{"Explorer les types associés de Rust"}} rust/operator_overloading -.-> lab-99354{{"Explorer les types associés de Rust"}} end

Types associés

L'utilisation de "types associés" améliore la lisibilité globale du code en déplaçant les types internes localement dans un trait en tant que types de sortie. La syntaxe de la définition du trait est la suivante :

// `A` et `B` sont définis dans le trait via le mot clé `type`.
// (Remarque : `type` dans ce contexte est différent de `type` lorsqu'il est utilisé pour
// les alias).
trait Contains {
    type A;
    type B;

    // Syntaxe mise à jour pour faire référence à ces nouveaux types de manière générique.
    fn contains(&self, _: &Self::A, _: &Self::B) -> bool;
}

Remarquez que les fonctions qui utilisent le trait Contains n'ont plus besoin d'exprimer A ou B du tout :

// Sans utiliser des types associés
fn difference<A, B, C>(container: &C) -> i32 where
    C: Contains<A, B> {... }

// En utilisant des types associés
fn difference<C: Contains>(container: &C) -> i32 {... }

Réécrivons l'exemple de la section précédente en utilisant des types associés :

struct Container(i32, i32);

// Un trait qui vérifie si 2 éléments sont stockés dans le conteneur.
// Récupère également la première ou la dernière valeur.
trait Contains {
    // Définissez ici des types génériques que les méthodes pourront utiliser.
    type A;
    type B;

    fn contains(&self, _: &Self::A, _: &Self::B) -> bool;
    fn first(&self) -> i32;
    fn last(&self) -> i32;
}

impl Contains for Container {
    // Spécifiez quels types sont `A` et `B`. Si le type `input`
    // est `Container(i32, i32)`, les types `output` sont déterminés
    // comme étant `i32` et `i32`.
    type A = i32;
    type B = i32;

    // `&Self::A` et `&Self::B` sont également valides ici.
    fn contains(&self, number_1: &i32, number_2: &i32) -> bool {
        (&self.0 == number_1) && (&self.1 == number_2)
    }
    // Récupérez le premier nombre.
    fn first(&self) -> i32 { self.0 }

    // Récupérez le dernier nombre.
    fn last(&self) -> i32 { self.1 }
}

fn difference<C: Contains>(container: &C) -> i32 {
    container.last() - container.first()
}

fn main() {
    let number_1 = 3;
    let number_2 = 10;

    let container = Container(number_1, number_2);

    println!("Le conteneur contient-il {} et {} : {}",
        &number_1, &number_2,
        container.contains(&number_1, &number_2));
    println!("Premier nombre : {}", container.first());
    println!("Dernier nombre : {}", container.last());

    println!("La différence est : {}", difference(&container));
}

Sommaire

Félicitations ! Vous avez terminé le laboratoire sur les Types associés. Vous pouvez pratiquer d'autres laboratoires sur LabEx pour améliorer vos compétences.