Generische Methoden
Teil des Abschnitts Objektorientierte Programmierung der Rust-Journey von Coddy. Lektion 25 von 61.
Eine generische Struktur kann jeden Typ enthalten, ist aber ohne Methoden, mit denen du auf ihre Daten zugreifen kannst, nicht sehr nützlich. Um Methoden für eine generische Struktur zu definieren, brauchst du eine spezielle Syntax im impl-Block.
Entscheidend ist, den generischen Parameter direkt beim impl selbst zu deklarieren:
struct Wrapper<T> {
value: T,
}
impl<T> Wrapper<T> {
fn get(&self) -> &T {
&self.value
}
}
Beachte das impl<T> vor Wrapper<T>. Dadurch wird Rust mitgeteilt, dass T ein generischer Typparameter für den gesamten Implementierungsblock ist. Ohne diese Deklaration würde Rust nach einem konkreten Typ namens T suchen und ihn nicht finden.
Die Methode get gibt &T zurück: eine Referenz auf den Typ, den der Wrapper enthält. Das funktioniert unabhängig davon, ob T eine Ganzzahl, eine Zeichenkette oder ein anderer Typ ist:
let num_wrapper = Wrapper { value: 100 };
let text_wrapper = Wrapper { value: "Rust" };
println!("{}", num_wrapper.get()); // 100
println!("{}", text_wrapper.get()); // Rust
Dieselbe Methodendefinition funktioniert für beide, weil sich der generische Typ T zur Kompilierzeit an jeden konkreten Typ anpasst.
Aufgabe
EinfachErweitern wir deinen generischen Container um Methoden! Du erstellst eine Struktur Box (nicht zu verwechseln mit Rusts standardmäßiger Box), die beliebige Typen enthalten und Methoden für den Zugriff auf ihren Inhalt bereitstellen kann.
Du organisierst deinen Code auf zwei Dateien:
mybox.rs: Definiere eine öffentliche generische Struktur namensMyBox<T>mit einem privaten Feldcontentsvom TypT. Implementiere Methoden für diese Struktur:- Eine assoziierte Funktion
new, die mit dem angegebenen Wert ein neuesMyBoxerstellt - Eine Methode
peek, die eine Referenz auf den Inhalt zurückgibt (mit&self) - Eine Methode
replace, die einen neuen Wert entgegennimmt und den aktuellen Inhalt ersetzt (mit&mut self)
- Eine assoziierte Funktion
main.rs: Binde dein Modul ein und zeige, wie die generischen Methoden mit unterschiedlichen Typen funktionieren. Du erstellst Boxen, schaust dir ihren Inhalt an und ersetzt Werte, um die Methoden in Aktion zu zeigen.
Denke an die wichtige Syntax zum Implementieren von Methoden für eine generische Struktur: Vor MyBox<T> brauchst du impl<T>, um Rust mitzuteilen, dass T ein generischer Parameter für den gesamten Implementierungsblock ist.
Zeige in deiner Hauptdatei die Verwendung von MyBox, indem du:
- Eine Box mit einer Ganzzahl erstellst (erste Eingabe, als
i32geparst) - Den Inhalt abfragst und den Wert ausgibst
- Den Inhalt durch eine neue Ganzzahl ersetzt (zweite Eingabe, als
i32geparst) - Den Inhalt erneut abfragst, um den aktualisierten Wert zu zeigen
- Eine zweite Box mit einer Zeichenkette erstellst (dritte Eingabe)
- Den Inhalt der Zeichenketten-Box abfragst
Deine Ausgabe sollte diesem Format entsprechen:
Integer box contains: {value}
After replace: {value}
String box contains: {value}Zum Beispiel mit den Eingaben 10, 25 und Rust:
Integer box contains: 10
After replace: 25
String box contains: RustDu erhältst drei Eingaben: eine anfängliche Ganzzahl, eine Ersatz-Ganzzahl und einen Zeichenkettenwert.
Probier es selbst
mod mybox;
use mybox::MyBox;
fn main() {
// Eingaben einlesen
let mut input1 = String::new();
std::io::stdin().read_line(&mut input1).expect("Failed to read line");
let initial_int: i32 = input1.trim().parse().expect("Invalid integer");
let mut input2 = String::new();
std::io::stdin().read_line(&mut input2).expect("Failed to read line");
let replacement_int: i32 = input2.trim().parse().expect("Invalid integer");
let mut input3 = String::new();
std::io::stdin().read_line(&mut input3).expect("Failed to read line");
let string_value = input3.trim().to_string();
// TODO: Eine MyBox mit der ursprünglichen Ganzzahl erstellen
// TODO: Den Inhalt ansehen und ausgeben: "Integer box contains: {value}"
// TODO: Den Inhalt durch die neue Ganzzahl ersetzen
// TODO: Den Inhalt erneut ansehen und ausgeben: "After replace: {value}"
// TODO: Eine zweite MyBox mit dem Zeichenfolgenwert erstellen
// TODO: Den Inhalt der Zeichenfolgenbox ansehen und ausgeben: "String box contains: {value}"
}
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