Implémentation de traits génériques pour des conteneurs

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 avons un trait appelé Contains qui est générique sur son type de conteneur et nécessite une spécification explicite de ses types génériques lorsqu'il est implémenté pour le type Container.

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/AdvancedTopicsGroup(["Advanced Topics"]) rust(("Rust")) -.-> rust/BasicConceptsGroup(["Basic Concepts"]) rust(("Rust")) -.-> rust/DataTypesGroup(["Data Types"]) rust(("Rust")) -.-> rust/FunctionsandClosuresGroup(["Functions and Closures"]) rust(("Rust")) -.-> rust/MemorySafetyandManagementGroup(["Memory Safety and Management"]) rust(("Rust")) -.-> rust/DataStructuresandEnumsGroup(["Data Structures and Enums"]) rust/BasicConceptsGroup -.-> rust/variable_declarations("Variable Declarations") rust/DataTypesGroup -.-> rust/integer_types("Integer Types") rust/FunctionsandClosuresGroup -.-> rust/function_syntax("Function Syntax") rust/FunctionsandClosuresGroup -.-> rust/expressions_statements("Expressions and Statements") rust/MemorySafetyandManagementGroup -.-> rust/lifetime_specifiers("Lifetime Specifiers") 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-99353{{"Implémentation de traits génériques pour des conteneurs"}} rust/integer_types -.-> lab-99353{{"Implémentation de traits génériques pour des conteneurs"}} rust/function_syntax -.-> lab-99353{{"Implémentation de traits génériques pour des conteneurs"}} rust/expressions_statements -.-> lab-99353{{"Implémentation de traits génériques pour des conteneurs"}} rust/lifetime_specifiers -.-> lab-99353{{"Implémentation de traits génériques pour des conteneurs"}} rust/method_syntax -.-> lab-99353{{"Implémentation de traits génériques pour des conteneurs"}} rust/traits -.-> lab-99353{{"Implémentation de traits génériques pour des conteneurs"}} rust/operator_overloading -.-> lab-99353{{"Implémentation de traits génériques pour des conteneurs"}} end

Le problème

Un trait qui est générique sur son type de conteneur a des exigences de spécification de type - les utilisateurs du trait doivent spécifier tous ses types génériques.

Dans l'exemple ci-dessous, le trait Contains autorise l'utilisation des types génériques A et B. Le trait est ensuite implémenté pour le type Container, en spécifiant i32 pour A et B de manière à ce qu'il puisse être utilisé avec fn difference().

Étant donné que Contains est générique, nous sommes contraints d'explicitement spécifier tous les types génériques pour fn difference(). En pratique, nous souhaitons trouver un moyen d'exprimer que A et B sont déterminés par l'entrée C. Comme vous le verrez dans la section suivante, les types associés offrent exactement cette capacité.

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<A, B> {
    fn contains(&self, _: &A, _: &B) -> bool; // Exige explicitement `A` et `B`.
    fn first(&self) -> i32; // N'exige pas explicitement `A` ou `B`.
    fn last(&self) -> i32;  // N'exige pas explicitement `A` ou `B`.
}

impl Contains<i32, i32> for Container {
    // Vrai si les nombres stockés sont égaux.
    fn contains(&self, number_1: &i32, number_2: &i32) -> bool {
        (&self.0 == number_1) && (&self.1 == number_2)
    }

    // Récupère le premier nombre.
    fn first(&self) -> i32 { self.0 }

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

// `C` contient `A` et `B`. Compte tenu de cela, devoir exprimer `A` et
// `B` à nouveau est gênant.
fn difference<A, B, C>(container: &C) -> i32 where
    C: Contains<A, B> {
    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 Le problème. Vous pouvez pratiquer d'autres laboratoires sur LabEx pour améliorer vos compétences.