Menu
Coddy logo textTech

Die Where-Klausel

Teil des Abschnitts Objektorientierte Programmierung der Rust-Journey von Coddy. Lektion 42 von 61.

Wenn du weitere Trait-Bounds hinzufügst, können Funktionssignaturen schwer lesbar werden. Betrachte eine Funktion mit mehreren generischen Parametern, von denen jeder mehrere Traits erfordert:

fn complex_operation<T: Display + Clone, U: Debug + Summary>(first: T, second: U) {
    // ...
}

Das funktioniert, aber die Signatur wird zunehmend überladen. Die where-Klausel bietet eine übersichtlichere Alternative, indem sie die Trait-Grenzen hinter die Parameterliste verschiebt:

fn complex_operation<T, U>(first: T, second: U)
where
    T: Display + Clone,
    U: Debug + Summary,
{
    // ...
}

Beide Versionen sind funktional identisch: Die where-Klausel dient ausschließlich der Lesbarkeit. Die Anforderungen jedes Typs stehen in einer eigenen Zeile, sodass sich leicht erfassen lässt, was jeder generische Parameter benötigt.

Die where-Klausel wird besonders wertvoll, wenn Einschränkungen komplex sind oder wenn du viele generische Parameter hast. Sie hält den Funktionsnamen und die Parameter auf einen Blick sichtbar, während die Einschränkungen darunter separat aufgeführt werden. Dies ist der bevorzugte Stil in den meisten Rust-Codebasen, wenn die Einschränkungen über ein einfaches T: Trait hinausgehen.

challenge icon

Aufgabe

Einfach

Erstelle ein Datenverarbeitungssystem, das die where-Klausel verwendet, damit komplexe Trait-Bounds lesbar bleiben! Du erstellst eine generische Funktion mit mehreren Typparametern, von denen jeder unterschiedliche Traits erfordert, und organisierst die Bounds übersichtlich mithilfe der where-Syntax.

Du organisierst deinen Code auf zwei Dateien:

  • processor.rs: Definiere zwei öffentliche Traits und eine generische Funktion, die beide verwendet:
    • Summarize: ein Trait mit einer summary-Methode, die &self übernimmt und einen String zurückgibt
    • Validate: ein Trait mit einer validate-Methode, die &self übernimmt und einen bool zurückgibt
    Erstelle anschließend eine öffentliche generische Funktion namens process_items, die zwei Parameter unterschiedlicher generischer Typen akzeptiert. Verwende eine where-Klausel, um festzulegen, dass der erste Typ sowohl Clone als auch Summarize implementieren muss, während der zweite Typ Validate implementieren muss. Die Funktion soll die Zusammenfassung des ersten Elements ausgeben und anschließend ausgeben, ob das zweite Element gültig ist.
  • main.rs: Erstelle zwei öffentliche Structs, die die erforderlichen Traits implementieren:
    • Article: mit einem öffentlichen Feld title (String). Implementiere Summarize, sodass Article: {title} zurückgegeben wird, und leite Clone ab.
    • Form: mit einem öffentlichen Feld filled (bool). Implementiere Validate, sodass der Wert von filled zurückgegeben wird.
    Verwende die bereitgestellten Eingaben, um ein Article und ein Form zu erstellen, und rufe anschließend process_items mit beiden auf.

Die where-Klausel macht deine Funktionssignatur deutlich übersichtlicher, als wenn du alle Bounds in die spitzen Klammern packen würdest. Die Anforderungen jedes Typs erscheinen in einer eigenen Zeile, sodass leicht zu erkennen ist, was jeder generische Parameter benötigt.

Deine Ausgabe sollte die Zusammenfassung gefolgt vom Validierungsergebnis anzeigen:

Article: {title}
Valid: {true/false}

Zum Beispiel mit den Eingaben Rust Tips und true:

Article: Rust Tips
Valid: true

Und mit den Eingaben Breaking News und false:

Article: Breaking News
Valid: false

Du erhältst zwei Eingaben: den Artikeltitel und die Information, ob das Formular ausgefüllt ist (als bool parsen).

Probier es selbst

mod processor;

use processor::{Summarize, Validate, process_items};
use std::io;

// TODO: Definiere eine öffentliche struct Article mit einem öffentlichen title-Feld (String)
// Leite Clone für Article ab

// TODO: Implementiere Summarize für Article
// Die summary-Methode sollte "Article: {title}" zurückgeben

// TODO: Definiere eine öffentliche struct Form mit einem öffentlichen filled-Feld (bool)

// TODO: Implementiere Validate für Form
// Die validate-Methode sollte den Wert von filled zurückgeben

fn main() {
    let mut title = String::new();
    io::stdin().read_line(&mut title).expect("Failed to read line");
    let title = title.trim().to_string();

    let mut filled_input = String::new();
    io::stdin().read_line(&mut filled_input).expect("Failed to read line");
    let filled: bool = filled_input.trim().parse().expect("Failed to parse bool");

    // TODO: Erstelle ein Article mit dem gegebenen title
    
    // TODO: Erstelle ein Form mit dem gegebenen filled-Wert
    
    // TODO: Rufe process_items mit dem article und form auf
}
quiz iconTeste dich selbst

Diese Lektion enthält ein kurzes Quiz. Starte die Lektion, um es zu beantworten und deinen Fortschritt zu speichern.

Alle Lektionen in Objektorientierte Programmierung

Übe selbstständig: Online-Rust-Compiler