Das Newtype-Pattern
Umschließen Sie Typen für mehr Sicherheit und Klarheit.
Das Newtype-Pattern ist eine kostenlose Learn Rust Coding-Lektion auf CoddyKit. Dies ist Lektion 2 von 4. Du kannst die komplette Lektion unten kostenlos lesen – dann übst du sie direkt im Browser mit einem integrierten Code-Editor und einem KI-Tutor rund um die Uhr. Sie ist Teil des Learn Rust Coding-Lernpfads, und dein Fortschritt wird über Web und CoddyKit-App synchronisiert. Der Learn Rust Coding-Kurs umfasst insgesamt 4 Lektionen.
Was ist ein Newtype?
Ein Newtype ist eine Tupelstruktur mit genau einem Feld, die einen vorhandenen Typ umschließt und ihm eine eigene Identität gibt. struct Meters(f64) ist ein vollständig neuer Typ, obwohl er ein einfaches f64 enthält.
Der Wrapper verursacht keine Laufzeitkosten, ermöglicht es dem Compiler aber, eine Bedeutung durchzusetzen, die ein primitives Rohformat nicht ausdrücken kann.
struct Meters(f64);
struct Seconds(f64);Verwechslungen von Einheiten verhindern
Primitive Rohdatentypen lassen sich leicht verwechseln. Wenn sowohl eine Entfernung als auch eine Zeit als f64 dargestellt werden, hindert Sie nichts daran, sie bei einem Aufruf zu vertauschen.
Wenn Sie beide Werte in jeweils einen eigenen Newtype verpacken, werden solche Fehler zu Kompilierfehlern statt zu unbemerkten Fehlern.
fn speed(d: Meters, t: Seconds) -> f64 {
d.0 / t.0
}
// speed(Seconds(2.0), Meters(10.0)) -> compile errorAuf den enthaltenen Wert zugreifen
Über den Tupelindex .0 gelangen Sie an den umschlossenen Wert. Viele Newtypes stellen außerdem eine Methode bereit oder implementieren From, um ergonomische Konvertierungen zu ermöglichen.
struct UserId(u64);
impl UserId {
fn value(&self) -> u64 { self.0 }
}
fn main() {
let id = UserId(42);
println!("id = {}", id.value());
}Invarianten kapseln
Halten Sie das innere Feld privat und validieren Sie es in einem Konstruktor. Dann ist jeder Wert des Newtypes garantiert gültig, sodass nachgelagerter Code keine erneute Prüfung benötigt.
pub struct Email(String);
impl Email {
pub fn new(s: &str) -> Option<Email> {
if s.contains('@') {
Some(Email(s.to_string()))
} else {
None
}
}
}Die Orphan-Regel
Rust verbietet es, ein fremdes Trait für einen fremden Typ zu implementieren. Sie können nicht impl Display for Vec<T> schreiben, weil weder das Trait noch der Typ Ihnen gehört.
Diese Regel hält die Trait-Kohärenz über Crates hinweg intakt, kann aber nützliche Implementierungen verhindern.
Newtypes umgehen die Orphan-Regel
Da der Newtype in Ihrer Crate definiert ist, besitzen Sie nun einen lokalen Typ und dürfen jedes Trait für ihn implementieren. Dies ist die standardmäßige Lösung für die Orphan-Regel.
use std::fmt;
struct Wrapper(Vec<String>);
impl fmt::Display for Wrapper {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "[{}]", self.0.join(", "))
}
}Ein ausführbarer Wrapper mit Display
Hier wird der Wrapper aus der vorherigen Szene verwendet. Da wir Wrapper besitzen, ist es erlaubt, Display dafür zu implementieren, und das Programm gibt die zusammengefügte Liste aus.
use std::fmt;
struct Wrapper(Vec<String>);
impl fmt::Display for Wrapper {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "[{}]", self.0.join(", "))
}
}
fn main() {
let w = Wrapper(vec!["a".into(), "b".into()]);
println!("{}", w);
}Die API-Oberfläche einschränken
Durch das Wrapping eines leistungsfähigen Typs können Sie nur eine sichere Teilmenge davon bereitstellen. Ein NonEmptyVec kann verändernde Methoden verbergen, durch die es leer werden könnte, und so seine Invariante bewahren.
pub struct NonEmptyVec<T>(Vec<T>);
impl<T> NonEmptyVec<T> {
pub fn new(first: T) -> Self {
NonEmptyVec(vec![first])
}
pub fn first(&self) -> &T {
&self.0[0]
}
}Abstraktion ohne Laufzeitkosten
Ein Newtype mit einem Feld hat dasselbe Speicherlayout wie der umschlossene Wert. Der Compiler optimiert den Wrapper weg, sodass die Sicherheit hier zur Laufzeit tatsächlich kostenlos ist.
Das Hinzufügen von #[repr(transparent)] garantiert ein identisches Layout, was für FFI wichtig ist.
#[repr(transparent)]
struct Celsius(f64);Traits für Newtypes ableiten
Newtypes leiten häufig Standard-Traits ab, damit sie sich dort wie der innere Wert verhalten, wo dies sinnvoll ist. Durch das Ableiten bleiben sie für Schlüssel, Vergleiche und Debug-Ausgaben komfortabel verwendbar.
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
struct ProductId(u32);
fn main() {
let a = ProductId(7);
let b = a.clone();
println!("{:?} == {:?}: {}", a, b, a == b);
}Newtype oder Type-Alias
Verwechseln Sie einen Newtype nicht mit einem Type-Alias. type Meters = f64 ist lediglich ein Name; der Typ bleibt ein f64 und bietet keine zusätzliche Sicherheit.
Ein Newtype wie struct Meters(f64) ist dagegen ein wirklich eigenständiger Typ, den der Compiler getrennt behandeln kann.
type Km = f64; // alias: interchangeable with f64
struct Mi(f64); // newtype: distinct from f64Kurze Überprüfung
Entscheiden Sie, warum ein Newtype dort hilfreich ist, wo ein Type-Alias nicht ausreicht.
Zusammenfassung
Beim Newtype-Muster wird ein vorhandener Typ in eine Tupelstruktur mit einem Feld eingeschlossen, um bei null Laufzeitkosten eine eigene Identität zu erhalten. Es verhindert Verwechslungen von Werten, kapselt Invarianten hinter einem privaten Feld und umgeht die Orphan-Regel, sodass Sie fremde Traits implementieren können.
Anders als ein Type-Alias ist ein Newtype ein echter, eigenständiger Typ.
Häufig gestellte Fragen
Ist die Lektion „Das Newtype-Pattern“ kostenlos?
Ja — der vollständige Text von „Das Newtype-Pattern“ ist hier im Web kostenlos zu lesen. Um sie interaktiv zu üben (integrierter Code-Editor und 24/7 KI-Tutor) und den Rest des Learn Rust Coding-Kurses freizuschalten, upgrade auf CoddyKit PRO. Der Learn Rust Coding-Kurs umfasst insgesamt 4 Lektionen.
Was lerne ich in „Das Newtype-Pattern“?
Umschließen Sie Typen für mehr Sicherheit und Klarheit. Du übst Learn Rust Coding mit praktischem Code, den du direkt im Browser ausführst, und ein 24/7 KI-Tutor beantwortet deine Fragen während du die Lektion bearbeitest.
Brauche ich Erfahrung, um Learn Rust Coding zu starten?
Keine Vorkenntnisse erforderlich. Learn Rust Coding auf CoddyKit ist für Anfänger bis fortgeschrittene Lernende strukturiert, sodass du hier starten oder von Anfang an beginnen und in deinem eigenen Tempo voranschreiten kannst. Dies ist Lektion 2 von 4.
Wie lange dauert die Lektion „Das Newtype-Pattern“?
Die meisten CoddyKit-Lektionen dauern etwa 5–10 Minuten. Jede ist kompakt und interaktiv, sodass du stetig Fortschritte machst und genau dort weitermachst, wo du aufgehört hast – im Web und in der App.
Kann ich in dieser Learn Rust Coding-Lektion Code schreiben und ausführen?
Ja. Jede Learn Rust Coding-Lektion enthält einen integrierten Code-Editor, sodass du echten Code direkt in deinem Browser schreibst und ausführst und sofort KI-Feedback erhältst — ohne lokale Einrichtung erforderlich.
Alle Lektionen in diesem Kurs
- Das Builder-Pattern
- Das Newtype-Pattern
- Builder mit Type-State
- Deref und ergonomische Wrapper