Menu
Coddy logo textTech

Generische Structs

Teil des Abschnitts Object Oriented Programming der Rust-Journey von Coddy — Lektion 24 von 61.

Bisher hatte jedes Struct, das Sie erstellt haben, Felder mit spezifischen, konkreten Typen. Ein Pet hat einen String-Namen, ein Rectangle hat f64-Dimensionen. Aber was ist, wenn Sie ein Struct erstellen möchten, das jeden Datentyp enthalten kann?

Hier kommen Generics ins Spiel. Generics ermöglichen es Ihnen, flexiblen, wiederverwendbaren Code zu schreiben, der mit mehreren Typen funktioniert. Anstatt einen spezifischen Typ fest zu kodieren, verwenden Sie einen Platzhalter – normalerweise T –, der durch einen konkreten Typ ersetzt wird, wenn Sie das Struct verwenden.

Hier ist ein einfaches Wrapper-Struct, das jeden Typ aufnehmen kann:

struct Wrapper<T> {
    value: T,
}

Das <T> nach dem Struct-Namen deklariert einen generischen Typparameter. Innerhalb des Structs fungiert T als Platzhalter für den Typ, den Sie tatsächlich verwenden werden. Wenn Sie eine Instanz erstellen, leitet Rust den konkreten Typ ab:

let int_wrapper = Wrapper { value: 42 };        // T ist i32
let float_wrapper = Wrapper { value: 3.14 };    // T ist f64
let text_wrapper = Wrapper { value: "hello" };  // T ist &str

Jeder dieser Typen ist ein anderer konkreter Typ — Wrapper<i32>, Wrapper<f64> und Wrapper<&str> — aber sie alle teilen sich dieselbe Struct-Definition. Dies macht es unnötig, separate IntWrapper, FloatWrapper und StringWrapper Structs zu schreiben, die im Wesentlichen dasselbe tun.

Der Buchstabe T ist nur eine Konvention (kurz für „Type“). Man könnte jeden gültigen Bezeichner verwenden, aber T ist in Rust und den meisten anderen Sprachen mit Generics Standard.

challenge icon

Aufgabe

Einfach

Lassen Sie uns einen generischen Container bauen, der jeden Werttyp aufnehmen kann! Sie werden eine Container-Struktur erstellen, die zeigt, wie Generics Ihren Code flexibel und wiederverwendbar machen.

Sie werden Ihren Code über zwei Dateien organisieren:

  • container.rs: Definieren Sie eine öffentliche generische Struktur namens Container<T> mit einem einzigen öffentlichen Feld item vom Typ T. Dieser Container sollte in der Lage sein, jeden Typ aufzunehmen – Ganzzahlen, Fließkommazahlen, Strings oder alles andere.
  • main.rs: Binden Sie Ihr Container-Modul ein und demonstrieren Sie dessen Flexibilität, indem Sie Container erstellen, die verschiedene Datentypen enthalten. Sie werden drei Container erstellen und anzeigen, was jeder einzelne enthält.

Erstellen Sie in Ihrer Hauptdatei die folgenden Container:

  1. Einen Container, der einen Ganzzahlwert enthält (die erste Eingabe, geparst als i32)
  2. Einen Container, der einen Fließkommawert enthält (die zweite Eingabe, geparst als f64)
  3. Einen Container, der einen String enthält (die dritte Eingabe, beibehalten als String)

Ihre Ausgabe sollte den Inhalt jedes Containers in diesem Format anzeigen:

Integer container: {value}
Float container: {value}
String container: {value}

Zum Beispiel mit den Eingaben 42, 3.14 und hello:

Integer container: 42
Float container: 3.14
String container: hello

Beachten Sie, wie dieselbe Container<T>-Definition für alle drei verschiedenen Typen funktioniert – das ist die Macht der Generics!

Sie erhalten drei Eingaben: einen Ganzzahlwert, einen Fließkommawert und einen String-Wert.

Spickzettel

Generics ermöglichen es Ihnen, Structs zu erstellen, die mithilfe eines Typparameter-Platzhalters beliebige Datentypen enthalten können.

Um ein generisches Struct zu deklarieren, verwenden Sie spitze Klammern mit einem Typparameter (üblicherweise T):

struct Wrapper<T> {
    value: T,
}

Das <T> deklariert einen generischen Typparameter, und T innerhalb des Structs fungiert als Platzhalter für den tatsächlichen Typ.

Beim Erstellen von Instanzen leitet Rust den konkreten Typ ab:

let int_wrapper = Wrapper { value: 42 };        // T ist i32
let float_wrapper = Wrapper { value: 3.14 };    // T ist f64
let text_wrapper = Wrapper { value: "hello" };  // T ist &str

Jede Instanz wird zu einem anderen konkreten Typ (Wrapper<i32>, Wrapper<f64>, Wrapper<&str>), während sie dieselbe Struct-Definition teilen.

Probier es selbst

mod container;

use container::Container;

fn main() {
    // Die drei Eingaben lesen
    let mut input1 = String::new();
    std::io::stdin().read_line(&mut input1).expect("Failed to read line");
    let int_value: i32 = input1.trim().parse().expect("Failed to parse integer");

    let mut input2 = String::new();
    std::io::stdin().read_line(&mut input2).expect("Failed to read line");
    let float_value: f64 = input2.trim().parse().expect("Failed to parse float");

    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: Drei Container mit Container<T> erstellen
    // 1. Ein Integer-Container, der int_value enthält
    // 2. Ein Float-Container, der float_value enthält
    // 3. Ein String-Container, der string_value enthält

    // TODO: Den Inhalt jedes Containers im erforderlichen Format ausgeben
    // Integer container: {value}
    // Float container: {value}
    // String container: {value}
}
quiz iconTeste dich selbst

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