Structs sind in Rust der zentrale Mechanismus für eigene Datentypen. Sie kombinieren Felder zu einer benannten Einheit, lassen sich mit Methoden und Konstanten ausstatten, automatisch mit Standard-Traits versehen (derive) und in mächtige Patterns wie Builder und Newtype einbetten. Anders als Klassen in Java oder C# trennt Rust Daten (Struct) und Verhalten (impl-Block) strikt — ein bewusster Bruch mit OOP, der Polymorphismus über Traits realisiert statt über Vererbung. Dieses Kapitel führt durch alle drei Struct-Varianten, zeigt die impl-Block-Mechanik, klärt derive mit allen wichtigen Standard-Traits und schließt mit zwei zentralen Patterns: Builder für konfigurierbare APIs und Newtype für typsichere Wrapper.

Drei Struct-Varianten

Rust kennt drei syntaktische Formen, einen Struct zu deklarieren — jede mit eigener Bedeutung:

Rust Die drei Formen
// 1. Field-Struct (klassisch, benannte Felder)
struct Person {
    name: String,
    alter: u32,
}

// 2. Tuple-Struct (positionale Felder, keine Namen)
struct Punkt(f64, f64);

// 3. Unit-Struct (keine Felder)
struct Marker;

Wann welche?

FormWann nutzen
Field-StructDefault — sobald die Felder Bedeutung haben
Tuple-StructNewtype-Wrapper, kleine geometrische Typen
Unit-StructMarker-Typen, Trait-Implementierungen ohne Daten

Daten + Verhalten = Struct + impl

Das wichtigste konzeptuelle Pattern: Daten und Verhalten sind getrennt:

Rust Trennung
struct Konto {
    saldo_cent: i64,
}

impl Konto {
    fn neu() -> Self {
        Konto { saldo_cent: 0 }
    }

    fn einzahlen(&mut self, cent: i64) {
        self.saldo_cent += cent;
    }

    fn saldo(&self) -> i64 {
        self.saldo_cent
    }
}

Der struct-Block definiert die Daten. Der impl-Block fügt Methoden hinzu. Die zwei sind syntaktisch getrennt — was den großen Vorteil hat, dass du Methoden zu Stdlib-Typen wie Vec<T> über eigene Traits hinzufügen kannst, ohne deren Definition zu ändern.

Anders als bei OOP-Klassen gibt es keine Vererbung. Polymorphismus läuft über Traits — ein eigenes Kapitel im weiteren Verlauf.

Was dich erwartet

  • Struct-Grundlagen — Field-Structs als Default-Form. Deklaration, Konstruktion, Field-Access, Update-Syntax .., Pattern-Destrukturierung und Memory-Layout.
  • Tuple-Structs — Structs mit positionalen Feldern. Wann sie besser sind als Field-Structs, der spezielle Newtype-Case mit einem Feld.
  • Unit-Structs — Structs ohne Felder. Marker-Typen, Phantom-Typen, Trait-Implementierungen.
  • impl-Blocks und Methodenimpl-Blöcke im Detail. Methoden mit &self, &mut self, self. Mehrere impl-Blöcke. Inherent vs. Trait-Methoden.
  • Associated Functions — Funktionen, die zum Typ gehören, nicht zur Instanz. Konto::neu(), String::from(...). Der Konstruktor-Idiom.
  • derive-Makro-Grundlagen#[derive(Debug, Clone, PartialEq, Eq, Hash)] und Co. Wann was, welche Voraussetzungen, was die Macros generieren.
  • Builder-Pattern — Konfigurierbare Konstruktoren mit Method-Chaining. Konsumierende Builder, mutable Builder, derive_builder-Crate.
  • Newtype-Patternstruct Meter(f64) als typsicherer Wrapper. Wann ein Newtype-Wrapper besser ist als ein Type-Alias, Wrapper über Stdlib-Typen mit eigenen Traits.

Was du nach diesem Kapitel kannst

  • Eigene Datentypen mit der passenden Struct-Form deklarieren (Field/Tuple/Unit).
  • Methoden in impl-Blöcken sauber organisieren — mit korrekt gewählten Receiver-Typen (&self/&mut self/self).
  • Konstruktor-Funktionen als Associated Functions schreiben.
  • Standard-Traits per derive automatisch ableiten und wissen, welche Voraussetzungen die Felder erfüllen müssen.
  • Builder-Patterns für konfigurierbare APIs entwerfen.
  • Newtype-Wrapper für typsichere Domänen-Typen einsetzen — UserId(u64) statt u64, Meter(f64) statt f64.

Das nächste Kapitel geht zu Enums und Pattern Matching — Sum-Types, Option<T>, Result<T, E> und exhaustives match.

Weiterführende Ressourcen

Externe Quellen

/ Weiter

Zurück zu Structs & Methoden

Zur Übersicht