Traits implementieren
Teil des Abschnitts Object Oriented Programming der Rust-Journey von Coddy — Lektion 30 von 61.
Nachdem Sie nun wissen, wie man ein Trait definiert, sehen wir uns an, wie man ein Struct diesen Vertrag erfüllen lässt. Das Implementieren eines Traits verbindet die abstrakte Anforderung mit konkretem Verhalten.
Die Syntax verwendet impl TraitName for StructName:
trait Speak {
fn speak(&self) -> String;
}
struct Dog {
name: String,
}
impl Speak for Dog {
fn speak(&self) -> String {
format!("{} says: Woof!", self.name)
}
}
Der impl Speak for Dog-Block teilt Rust mit, dass Dog das Speak-Trait implementiert. Darin geben Sie den eigentlichen Methodenkörper an – hier definieren Sie, wie ein Hund spricht.
Die Stärke von Traits wird deutlich, wenn mehrere Typen denselben implementieren:
struct Cat {
name: String,
}
impl Speak for Cat {
fn speak(&self) -> String {
format!("{} says: Meow!", self.name)
}
}
Sowohl Dog als auch Cat teilen sich nun die Speak-Fähigkeit, aber jeder bietet seine eigene, einzigartige Implementierung. Sie können .speak() für beide Typen aufrufen:
let dog = Dog { name: String::from("Rex") };
let cat = Cat { name: String::from("Whiskers") };
println!("{}", dog.speak()); // Rex sagt: Woof!
println!("{}", cat.speak()); // Whiskers sagt: Meow!
Dies ist die Grundlage der Polymorphie in Rust – verschiedene Typen, dieselbe Schnittstelle, einzigartige Verhaltensweisen.
Aufgabe
EinfachLassen Sie uns Traits zum Leben erwecken, indem wir sie für verschiedene Typen implementieren! Sie werden einen Describable-Trait erstellen und ihn für zwei verschiedene Structs implementieren, von denen jedes seine eigene, einzigartige Beschreibung liefert.
Sie werden Ihren Code über drei Dateien organisieren:
describable.rs: Definieren Sie einen öffentlichenDescribable-Trait mit einer Methodedescribe(&self) -> String.items.rs: Erstellen Sie zwei öffentliche Structs, die Ihren Trait implementieren:Bookmit einem öffentlichentitle-Feld (String)Moviemit einem öffentlichenname-Feld (String)
Describablemit seinem eigenen, einzigartigen Beschreibungsformat implementieren.main.rs: Führen Sie Ihre Module zusammen, erstellen Sie Instanzen beider Structs und rufen Sie derendescribe-Methoden auf, um zu zeigen, wie derselbe Trait unterschiedliche Ausgaben für verschiedene Typen erzeugt.
Ihr Book sollte sich selbst als Book: {title} beschreiben und Ihr Movie sollte sich selbst als Film: {name} beschreiben. Beachten Sie, wie jeder Typ denselben Vertrag erfüllt, aber mit seinem eigenen Verhalten!
Erstellen Sie in Ihrer Hauptdatei ein Buch und einen Film unter Verwendung der beiden bereitgestellten Eingaben und geben Sie dann deren Beschreibungen in separaten Zeilen aus.
Ihre Ausgabe sollte diesem Format folgen:
Book: {title}
Film: {name}Zum Beispiel mit den Eingaben 1984 und Inception:
Book: 1984
Film: InceptionSie erhalten zwei Eingaben: einen Buchtitel und einen Filmnamen.
Spickzettel
Um ein Trait für ein Struct zu implementieren, verwenden Sie die Syntax impl TraitName for StructName:
trait Speak {
fn speak(&self) -> String;
}
struct Dog {
name: String,
}
impl Speak for Dog {
fn speak(&self) -> String {
format!("{} says: Woof!", self.name)
}
}
Mehrere Typen können dasselbe Trait mit unterschiedlichen Verhaltensweisen implementieren:
struct Cat {
name: String,
}
impl Speak for Cat {
fn speak(&self) -> String {
format!("{} says: Meow!", self.name)
}
}
let dog = Dog { name: String::from("Rex") };
let cat = Cat { name: String::from("Whiskers") };
println!("{}", dog.speak()); // Rex sagt: Woof!
println!("{}", cat.speak()); // Whiskers sagt: Meow!
Dies ermöglicht Polymorphismus in Rust – verschiedene Typen teilen sich dieselbe Schnittstelle mit individuellen Implementierungen.
Probier es selbst
mod describable;
mod items;
use describable::Describable;
use items::{Book, Movie};
fn main() {
// Eingaben lesen
let mut title = String::new();
std::io::stdin().read_line(&mut title).expect("Failed to read line");
let title = title.trim().to_string();
let mut name = String::new();
std::io::stdin().read_line(&mut name).expect("Failed to read line");
let name = name.trim().to_string();
// TODO: Erstelle eine Book-Instanz mit dem Titel
// TODO: Erstelle eine Movie-Instanz mit dem Namen
// TODO: Gib die Beschreibung des Buches aus
// TODO: Gib die Beschreibung des Films aus
}
Diese Lektion enthält ein kurzes Quiz. Starte die Lektion, um es zu beantworten und deinen Fortschritt zu speichern.
Alle Lektionen in Object Oriented Programming
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