Mehrfache Bounds
Teil des Abschnitts Objektorientierte Programmierung der Rust-Journey von Coddy. Lektion 41 von 61.
Manchmal reicht eine einzelne Trait-Beschränkung nicht aus. Du benötigst möglicherweise einen generischen Typ, der sowohl ausgegeben werden als auch eine Zusammenfassung bereitstellen kann. Rust ermöglicht es dir, mehrere Traits mithilfe der Syntax + zu verlangen.
So gibst du an, dass ein Typ zwei Traits implementieren muss:
use std::fmt::Display;
trait Summary {
fn summarize(&self) -> String;
}
fn announce<T: Display + Summary>(item: T) {
println!("Breaking news: {}", item);
println!("Summary: {}", item.summarize());
}
Die Bound T: Display + Summary bedeutet: „T muss sowohl Display als auch Summary implementieren.“ Innerhalb der Funktion kannst du die Fähigkeiten beider Traits verwenden: mit {} ausgeben (von Display) und summarize() aufrufen (von Summary).
Du kannst so viele Traits verketten, wie du benötigst:
fn process<T: Display + Summary + Clone>(item: T) {
// Kann ausgeben, zusammenfassen UND klonen
}
Dieses Muster ist unerlässlich, wenn deine Funktion auf mehreren Verhaltensweisen beruht. Statt jeden beliebigen Typ zu akzeptieren und zu hoffen, dass es funktioniert, deklarierst du ausdrücklich, welche Fähigkeiten genau erforderlich sind, und der Compiler setzt dies zur Kompilierungszeit durch.
Aufgabe
EinfachLass uns ein Produktinspektionssystem entwickeln, bei dem Elemente mehrere Fähigkeiten benötigen! Du erstellst eine generische Funktion, die nur Typen akzeptiert, die sowohl ein benutzerdefiniertes Trait als auch ein Standard-Trait implementieren, und demonstrierst damit, wie die Syntax + mehrere Bounds kombiniert.
Du organisierst deinen Code über zwei Dateien:
product.rs: Definiere ein öffentlichesInspectable-Trait mit einer Methode namensinspect, die&selfübernimmt und einenStringmit Inspektionsdetails zurückgibt. Erstelle anschließend eine öffentlicheGadget-Struktur mit den öffentlichen Feldernname(String) undserial(u32). Dein Gadget soll sowohlInspectable(mit der RückgabeInspecting: {name}) als auchstd::fmt::Display(formatiert als{name} (SN: {serial})) implementieren. Erstelle schließlich eine öffentliche generische Funktion namensfull_report, die jeden TypTakzeptiert, der sowohlDisplayals auchInspectableimplementiert. Diese Funktion soll zwei Zeilen ausgeben: zuerst das Element mit dem Formatierer{}, danach das Ergebnis des Aufrufs voninspect().main.rs: Binde dein Produktmodul ein und erstelle mithilfe der bereitgestellten Eingaben eineGadget-Instanz. Rufefull_reportmit deinem Gadget auf, um zu zeigen, dass es beide Trait-Anforderungen erfüllt.
Die Stärke mehrerer Bounds besteht darin, dass deine Funktion full_report Fähigkeiten aus beiden Traits verwenden kann: Sie stellt das Element ansprechend dar UND ruft Inspektionsdetails ab – alles garantiert zur Compile-Zeit.
Deine Ausgabe sollte sowohl das Anzeigeformat als auch das Inspektionsergebnis zeigen:
{name} (SN: {serial})
Inspecting: {name}Beispielsweise bei den Eingaben Smartwatch und 98765:
Smartwatch (SN: 98765)
Inspecting: SmartwatchDu erhältst zwei Eingaben: den Namen des Gadgets und die Seriennummer (als u32 parsen).
Probier es selbst
mod product;
use product::{Gadget, full_report};
fn main() {
// Eingaben lesen
let mut name = String::new();
std::io::stdin().read_line(&mut name).expect("Failed to read line");
let name = name.trim().to_string();
let mut serial_input = String::new();
std::io::stdin().read_line(&mut serial_input).expect("Failed to read line");
let serial: u32 = serial_input.trim().parse().expect("Failed to parse serial");
// TODO: Erstelle eine Gadget-Instanz mit dem name und der serial
// TODO: Rufe full_report mit deinem gadget auf
}
Diese Lektion enthält ein kurzes Quiz. Starte die Lektion, um es zu beantworten und deinen Fortschritt zu speichern.
Alle Lektionen in Objektorientierte Programmierung
1Methoden und Verhalten
Einführung in ImplementierungsblöckeDer Self-ParameterVeränderliche MethodenAssoziierte FunktionenMehrere ImplementierungsblöckeMethod ChainingRückblick – Rechteck-Aktionen4Projekt: Virtuelles Haustier
Das Haustier definierenDas Haustier füttern7Standard-Traits
Das Debug-TraitDas Display-TraitClone und CopyGleichheits-TraitsZusammenfassung – Druckbarer Punkt10Projekt: Dokumentensystem
Das Draw-TraitText-Komponente2Kapselung und Module
Grundlagen der ModuleDas Public-SchlüsselwortPrivate FelderGetterSetterWiederholung – Sicherer Tresor5Generics
Generische StructsGenerische MethodenMehrere generische TypenGenerische FunktionenZusammenfassung - Koordinatenpunkt8Traits als Einschränkungen
Syntax für Trait BoundsMehrfache BoundsDie Where-KlauselTypen mit Traits zurückgebenRückblick – Generischer Drucker11Design Patterns in Rust
Newtype-PatternKompositionDas Drop-TraitFrom und IntoZusammenfassung – Smart Pointer Mock3Fortgeschrittene Enums
Enums mit DatenMethoden für EnumsMatching von DatenvariantenDas Option-Enum erneut betrachtetZusammenfassung – Shape-Enum6Definition von Traits
Was ist ein Trait?Traits implementierenStandardimplementierungenStandardimplementierungen überschreibenTraits mit ParameternZusammenfassung – Media PlayerÜbe selbstständig: Online-Rust-Compiler