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:
// 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?
| Form | Wann nutzen |
|---|---|
| Field-Struct | Default — sobald die Felder Bedeutung haben |
| Tuple-Struct | Newtype-Wrapper, kleine geometrische Typen |
| Unit-Struct | Marker-Typen, Trait-Implementierungen ohne Daten |
Daten + Verhalten = Struct + impl
Das wichtigste konzeptuelle Pattern: Daten und Verhalten sind getrennt:
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 Methoden —
impl-Blöcke im Detail. Methoden mit&self,&mut self,self. Mehrereimpl-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-Pattern —
struct 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
deriveautomatisch 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)stattu64,Meter(f64)stattf64.
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
- The Rust Book – Structs
- Rust Reference – Structs
- Rust by Example – Structures
- Rust API Guidelines – Predictability