Standardimplementierungen überschreiben
Teil des Abschnitts Objektorientierte Programmierung 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 das passiert, kannst du den Standard überschreiben, indem du deine eigene Implementierung im impl-Block bereitstellst.
Definiere die Methode einfach mit derselben Signatur, aber füge deine 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 sie vollständig durch seine eigene Version. Wenn du greet() für einen Robot aufrufst, verwendet Rust die benutzerdefinierte Implementierung:
let bot = Robot { id: 42 };
println!("{}", bot.greet()); // BEEP BOOP. Einheit 42 online.
Das gibt dir Flexibilität: Typen, die mit dem Standardverhalten 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
EinfachErstelle ein Benachrichtigungssystem, in dem verschiedene Alarmtypen ihre Nachrichten anpassen können! Du erstellst ein Trait mit einer Standardimplementierung. Anschließend verwendet ein Typ die Standardimplementierung, während ein anderer sie mit einem eigenen Verhalten überschreibt.
Du organisierst deinen Code über drei Dateien:
notifiable.rs: Definiere ein öffentlichesNotifiable-Trait mit einernotify(&self) -> String-Methode, die eine Standardimplementierung besitzt und"Alert: Something happened!"zurückgibt.alerts.rs: Erstelle zwei öffentliche Structs, die dein Trait auf unterschiedliche Weise implementieren:GenericAlert: ein Unit-Struct, das die Standardbenachrichtigung verwendet (leerer impl-Block)UrgentAlert: ein Struct mit einem öffentlichenmessage-Feld (String), das die Standardimplementierung überschreibt und"URGENT: {message}"zurückgibt, wobei{message}die gespeicherte Nachricht ist
main.rs: Führe deine Module zusammen und demonstriere beide Verhaltensweisen. Erstelle mithilfe der bereitgestellten Eingabe einGenericAlertund einUrgentAlertund gib anschließend ihre Benachrichtigungen aus.
Die wichtigste Erkenntnis ist, dass GenericAlert dank der Standardimplementierung kostenloses Verhalten erhält, während UrgentAlert eine eigene spezialisierte Version bereitstellt, indem es die Methode in seinem impl-Block definiert.
Deine Ausgabe sollte diesem Format entsprechen:
Alert: Something happened!
URGENT: {message}Zum Beispiel bei der Eingabe Server is down!:
Alert: Something happened!
URGENT: Server is down!Du erhältst eine Eingabe: die Nachricht für den dringenden Alarm.
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 Eingabenachricht
// 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 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