Implementierung eines generischen Container-Traits

RustRustBeginner
Jetzt üben

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

💡 Dieser Artikel wurde von AI-Assistenten übersetzt. Um die englische Version anzuzeigen, können Sie hier klicken

Einführung

In diesem Lab haben wir ein Merkmal namens Contains, das über seinen Containertyp generisch ist und die explizite Angabe seiner generischen Typen erfordert, wenn es für den Container-Typ implementiert wird.

Hinweis: Wenn das Lab keinen Dateinamen angibt, können Sie einen beliebigen Dateinamen verwenden. Beispielsweise können Sie main.rs verwenden und es mit rustc main.rs &&./main kompilieren und ausführen.


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/MemorySafetyandManagementGroup(["Memory Safety and Management"]) 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/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{{"Implementierung eines generischen Container-Traits"}} rust/integer_types -.-> lab-99353{{"Implementierung eines generischen Container-Traits"}} rust/function_syntax -.-> lab-99353{{"Implementierung eines generischen Container-Traits"}} rust/expressions_statements -.-> lab-99353{{"Implementierung eines generischen Container-Traits"}} rust/lifetime_specifiers -.-> lab-99353{{"Implementierung eines generischen Container-Traits"}} rust/method_syntax -.-> lab-99353{{"Implementierung eines generischen Container-Traits"}} rust/traits -.-> lab-99353{{"Implementierung eines generischen Container-Traits"}} rust/operator_overloading -.-> lab-99353{{"Implementierung eines generischen Container-Traits"}} end

Das Problem

Ein trait, der über seinen Containertyp generisch ist, hat Typangabevoraussetzungen - die Benutzer des traits müssen alle seine generischen Typen angeben.

Im folgenden Beispiel erlaubt das Contains-trait die Verwendung der generischen Typen A und B. Anschließend wird das trait für den Container-Typ implementiert, wobei i32 für A und B angegeben wird, damit es mit fn difference() verwendet werden kann.

Da Contains generisch ist, müssen wir alle generischen Typen für fn difference() explizit angeben. Im praktischen Einsatz möchten wir eine Möglichkeit haben, auszudrücken, dass A und B durch die Eingabe C bestimmt werden. Wie Sie im nächsten Abschnitt sehen werden, bieten assoziierte Typen genau diese Möglichkeit.

struct Container(i32, i32);

// Ein trait, das überprüft, ob 2 Elemente im Container gespeichert sind.
// Ruft auch den ersten oder letzten Wert ab.
trait Contains<A, B> {
    fn contains(&self, _: &A, _: &B) -> bool; // Erfordert explizit `A` und `B`.
    fn first(&self) -> i32; // Erfordert nicht explizit `A` oder `B`.
    fn last(&self) -> i32;  // Erfordert nicht explizit `A` oder `B`.
}

impl Contains<i32, i32> for Container {
    // True, wenn die gespeicherten Zahlen gleich sind.
    fn contains(&self, number_1: &i32, number_2: &i32) -> bool {
        (&self.0 == number_1) && (&self.1 == number_2)
    }

    // Holt die erste Zahl.
    fn first(&self) -> i32 { self.0 }

    // Holt die letzte Zahl.
    fn last(&self) -> i32 { self.1 }
}

// `C` enthält `A` und `B`. In Anbetracht dessen ist es lästig, `A` und
// `B` erneut auszudrücken.
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!("Enthält der Container {} und {}: {}",
        &number_1, &number_2,
        container.contains(&number_1, &number_2));
    println!("Erste Zahl: {}", container.first());
    println!("Letzte Zahl: {}", container.last());

    println!("Der Unterschied ist: {}", difference(&container));
}

Zusammenfassung

Herzlichen Glückwunsch! Sie haben das The Problem-Lab abgeschlossen. Sie können in LabEx weitere Labs ausprobieren, um Ihre Fähigkeiten zu verbessern.