Hintergrund
In Rust gibt es keine klassischen Konstruktoren wie in OOP-Sprachen, aber es gibt assoziierte Funktionen (häufig new), die das Konstruktormuster mit expliziter Initialisierung implementieren. Assoziierte Funktionen ermöglichen es, Instanzen von Strukturen mit vordefinierten Werten zu erstellen oder sie mit zusätzlicher Logik zu generieren (zum Beispiel mit Speicherreservierung).
Problem
Viele neigen dazu, nur new zu verwenden und vergessen andere Muster der Fabrikmethoden (zum Beispiel with_capacity) oder implementieren die Initialisierung von Strukturen (insbesondere mit privaten/öffentlichen Feldern) falsch, was zu Invarianzfehlern führen kann.
Lösung
Eine assoziierte Funktion vom Typ new wird durch impl implementiert und kann der einzige Einstiegspunkt zur Erstellung von Objekten mit Invarianten sein. Funktionen wie with_capacity bieten zusätzliche Möglichkeiten, wie die vorzeitige Zuweisung von Speicher.
Beispielcode:
pub struct MyBuffer { data: Vec<u8>, } impl MyBuffer { pub fn new() -> Self { MyBuffer { data: Vec::new() } } pub fn with_capacity(cap: usize) -> Self { MyBuffer { data: Vec::with_capacity(cap) } } }
Wichtige Merkmale:
Wenn new nicht implementiert wird, erstellt Rust es standardmäßig?
Nein. Es gibt keine automatische Generierung von new. Wenn die Methode nicht explizit implementiert ist, wird es sie nicht geben, auch wenn die Struktur nur öffentliche Felder hat.
Was ist der grundlegende Unterschied zwischen new und Default?
Default ist ein trait-Konstruktor, der nur dort aufgerufen werden kann, wo der Typ Default implementiert oder explizit davon abgeleitet hat. Er ist standardmäßig für generische Algorithmen, stimmt aber nicht immer mit new überein.
Kann man die Methoden new und with_capacity für private Strukturen verwenden?
Ja, die Methoden können öffentlich oder privat sein, aber die Erstellung eines öffentlichen Konstruktors für eine private Struktur erlaubt es den Nutzern nicht, Instanzen dieser Struktur außerhalb des Moduls zu erstellen.
Öffentliche Struktur ohne Invarianten, alle Felder sind öffentlich:
pub struct User { pub login: String, pub active: bool }
Vorteile:
Nachteile:
Felder privat, Erstellung nur über new, Invarianten sichergestellt:
pub struct User { login: String, active: bool } impl User { pub fn new(login: String) -> User { User { login, active: true } } }
Vorteile:
Nachteile: