Standardimplementierungen überschreiben
Teil des Abschnitts Object Oriented Programming der Rust-Journey von Coddy — Lektion 32 von 61.
Standardimplementierungen sind praktisch, aber manchmal benötigt ein Typ ein Verhalten, das vom Standard abweicht. Wenn dies der Fall ist, können Sie den Standard überschreiben, indem Sie Ihre eigene Implementierung im impl-Block bereitstellen.
Definieren Sie die Methode einfach mit derselben Signatur, aber fügen Sie Ihre eigene Logik hinzu:
trait Greet {
fn greet(&self) -> String {
String::from("Hello there!")
}
}
struct Robot {
id: u32,
}
impl Greet for Robot {
fn greet(&self) -> String {
format!("BEEP BOOP. Unit {} online.", self.id)
}
}
Obwohl Greet eine standardmäßige greet-Methode bereitstellt, ersetzt Robot diese vollständig durch seine eigene Version. Wenn Sie greet() auf einem Robot aufrufen, verwendet Rust die benutzerdefinierte Implementierung:
let bot = Robot { id: 42 };
println!("{}", bot.greet()); // BEEP BOOP. Einheit 42 online.
Dies bietet Ihnen Flexibilität – Typen, die mit dem Standard zufrieden sind, müssen nichts schreiben, während Typen, die ein spezialisiertes Verhalten benötigen, nur die Methoden überschreiben können, die für sie relevant sind. Das Trait garantiert weiterhin, dass jeder implementierende Typ über die Methode verfügt.
Aufgabe
EinfachLassen Sie uns ein Benachrichtigungssystem bauen, bei dem verschiedene Alarmtypen ihre Nachrichten anpassen können! Sie werden ein Trait mit einer Standardimplementierung erstellen und dann einen Typ dazu bringen, den Standard zu verwenden, während ein anderer ihn mit benutzerdefiniertem Verhalten überschreibt.
Sie werden Ihren Code über drei Dateien organisieren:
notifiable.rs: Definieren Sie ein öffentlichesNotifiable-Trait mit einer Methodenotify(&self) -> String, die eine Standardimplementierung hat, welche"Alert: Something happened!"zurückgibt.alerts.rs: Erstellen Sie zwei öffentliche Structs, die Ihr Trait unterschiedlich implementieren:GenericAlert— ein Unit-Struct, das die Standardbenachrichtigung verwendet (leerer impl-Block)UrgentAlert— ein Struct mit einem öffentlichenmessage-Feld (String), das den Standard überschreibt, um"URGENT: {message}"zurückzugeben, wobei{message}die gespeicherte Nachricht ist
main.rs: Führen Sie Ihre Module zusammen und demonstrieren Sie beide Verhaltensweisen. Erstellen Sie einGenericAlertund einUrgentAlertunter Verwendung der bereitgestellten Eingabe und geben Sie dann deren Benachrichtigungen aus.
Die entscheidende Erkenntnis hierbei ist, dass GenericAlert kostenloses Verhalten durch den Standard erhält, während UrgentAlert seine eigene spezialisierte Version bereitstellt, indem es die Methode in seinem impl-Block definiert.
Ihre Ausgabe sollte diesem Format folgen:
Alert: Something happened!
URGENT: {message}Zum Beispiel mit der Eingabe Server is down!:
Alert: Something happened!
URGENT: Server is down!Sie erhalten eine Eingabe: die Nachricht für den dringenden Alarm (Urgent Alert).
Spickzettel
Sie können Standard-Trait-Implementierungen überschreiben, indem Sie Ihre eigene Implementierung im impl-Block bereitstellen:
trait Greet {
fn greet(&self) -> String {
String::from("Hello there!")
}
}
struct Robot {
id: u32,
}
impl Greet for Robot {
fn greet(&self) -> String {
format!("BEEP BOOP. Unit {} online.", self.id)
}
}
let bot = Robot { id: 42 };
println!("{}", bot.greet()); // BEEP BOOP. Unit 42 online.
Typen, die kein benutzerdefiniertes Verhalten benötigen, können einen leeren impl-Block verwenden, um die Standardimplementierung zu akzeptieren, während Typen, die ein spezialisiertes Verhalten erfordern, bestimmte Methoden überschreiben können, indem sie diese mit derselben Signatur definieren.
Probier es selbst
mod notifiable;
mod alerts;
use alerts::{GenericAlert, UrgentAlert};
use notifiable::Notifiable;
fn main() {
// Eingabe für die dringende Alarmmeldung lesen
let mut input = String::new();
std::io::stdin().read_line(&mut input).expect("Failed to read line");
let message = input.trim().to_string();
// TODO: Erstelle eine GenericAlert-Instanz
// TODO: Erstelle eine UrgentAlert-Instanz mit der eingegebenen Nachricht
// TODO: Gib die Benachrichtigung von GenericAlert aus
// TODO: Gib die Benachrichtigung von UrgentAlert 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