Leer programmeren met Rust · Les

Het Newtype-patroon

Wikkel typen in voor veiligheid en duidelijkheid.

Les 2 van 413 stappen

Het Newtype-patroon is een gratis Leer programmeren met Rust-les op CoddyKit. Dit is les 2 van 4. Je kunt 3 lessen uit dit leerpad gratis volledig lezen — daarna ontgrendelt CoddyKit PRO alle lessen, plus praktische oefeningen met een ingebouwde code-editor en een AI-tutor die 24/7 beschikbaar is. Deze les maakt deel uit van het leertraject Leer programmeren met Rust. Je voortgang wordt gesynchroniseerd op het web en in de CoddyKit-app. De cursus Leer programmeren met Rust bevat in totaal 4 lessen.

Wat is een newtype?

Een newtype is een tuple-struct met één veld die een bestaand type omhult om het een eigen identiteit te geven. struct Meters(f64) is een volledig nieuw type, ook al bevat het een gewone f64.

De wrapper kost tijdens uitvoering niets extra's, maar laat de compiler betekenis afdwingen die een primitief type niet kan afdwingen.

struct Meters(f64);
struct Seconds(f64);

Verwarring tussen eenheden voorkomen

Primitieve typen zijn gemakkelijk door elkaar te halen. Als zowel een afstand als een tijd een f64 zijn, houdt niets je tegen om ze bij een aanroep om te wisselen.

Door elk type in een eigen newtype te verpakken, worden zulke vergissingen compilatiefouten in plaats van stille bugs.

fn speed(d: Meters, t: Seconds) -> f64 {
    d.0 / t.0
}
// speed(Seconds(2.0), Meters(10.0)) -> compile error

De ingesloten waarde benaderen

Je bereikt de ingesloten waarde via tuple-index .0. Veel newtypes bieden ook een methode aan of implementeren From voor handige conversies.

struct UserId(u64);
impl UserId {
    fn value(&self) -> u64 { self.0 }
}
fn main() {
    let id = UserId(42);
    println!("id = {}", id.value());
}

Invarianten inkapselen

Maak het ingesloten veld privé en valideer het in een constructor. Dan is elke waarde van het newtype gegarandeerd geldig en hoeft volgende code de waarde nooit opnieuw te controleren.

pub struct Email(String);
impl Email {
    pub fn new(s: &str) -> Option<Email> {
        if s.contains('@') {
            Some(Email(s.to_string()))
        } else {
            None
        }
    }
}

De orphanregel

Rust verbiedt het implementeren van een externe trait voor een extern type. Je kunt geen impl Display for Vec<T> schrijven, omdat je noch de trait noch het type bezit.

Deze regel houdt traitcoherentie tussen crates betrouwbaar, maar kan nuttige implementaties blokkeren.

Newtypes omzeilen de orphanregel

Omdat de newtype in je crate is gedefinieerd, bezit je nu een lokaal type en mag je er elke trait voor implementeren. Dit is de standaardoplossing voor de orphanregel.

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(", "))
    }
}

Een uitvoerbare Wrapper Display

Hier wordt de wrapper uit de vorige scène gebruikt. We bezitten Wrapper, dus het is toegestaan om Display ervoor te implementeren en het programma drukt de samengevoegde lijst af.

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);
}

Het API-oppervlak beperken

Door een krachtig type in te kapselen, kun je slechts een veilige subset beschikbaar maken. Een NonEmptyVec kan mutatiemethoden verbergen waarmee de waarde leeg zou kunnen worden, zodat de invariant behouden blijft.

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]
    }
}

Abstractie zonder runtimekosten

Een newtype met één veld heeft dezelfde geheugenindeling als de ingekapselde waarde. De compiler optimaliseert de wrapper weg, dus de veiligheid kost hier echt niets tijdens runtime.

Met #[repr(transparent)] garandeer je een identieke geheugenindeling, wat belangrijk is voor FFI.

#[repr(transparent)]
struct Celsius(f64);

Traits afleiden voor newtypes

Newtypes leiden vaak standaardtraits af, zodat ze zich waar passend gedragen als de interne waarde. Afleiden houdt ze praktisch bruikbaar als sleutels, voor vergelijkingen en voor foutopsporingsuitvoer.

#[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 versus type alias

Verwar een newtype niet met een type alias. type Meters = f64 is alleen een naam; het blijft een f64 en biedt geen extra veiligheid.

Een newtype, struct Meters(f64), is een echt afzonderlijk type dat de compiler gescheiden kan houden.

type Km = f64;       // alias: interchangeable with f64
struct Mi(f64);      // newtype: distinct from f64

Korte controle

Bepaal waarom een newtype helpt waar een type alias dat niet doet.

Samenvatting

Het newtypepatroon verpakt een bestaand type in een tuplestruct met één veld om een afzonderlijke identiteit te krijgen zonder runtimekosten. Het voorkomt dat waarden door elkaar worden gehaald, kapselt invarianten in achter een privéveld en omzeilt de orphanregel, zodat je externe traits kunt implementeren.

In tegenstelling tot een type alias is een newtype een echt, afzonderlijk type.

Gratis beginnen

Leer Rust met een AI-tutor — gratis

Schrijf echte code en voer die uit in je browser, krijg direct hulp van een AI-tutor die 24/7 beschikbaar is en ga verder waar je gebleven bent op het web of in de app.

Cursussen
39
Lessen
144

Veelgestelde vragen

Is de les “Het Newtype-patroon” gratis?

Ja — je kunt hier op het web alle 3 lessen van het leerpad Leer programmeren met Rust, waaronder “Het Newtype-patroon”, gratis volledig lezen. Daarna ontgrendelt CoddyKit PRO alle lessen, plus interactieve oefeningen met een ingebouwde code-editor en een AI-tutor die 24/7 beschikbaar is. De cursus Leer programmeren met Rust bevat in totaal 4 lessen.

Wat leer ik in “Het Newtype-patroon”?

Wikkel typen in voor veiligheid en duidelijkheid. Je oefent met Leer programmeren met Rust door code rechtstreeks in de browser uit te voeren. Een AI-begeleider die 24/7 beschikbaar is beantwoordt je vragen terwijl je de les doorwerkt.

Heb ik ervaring nodig om met Leer programmeren met Rust te beginnen?

Ervaring vooraf is niet nodig. Leer programmeren met Rust op CoddyKit is opgebouwd voor beginners tot gevorderden, zodat je hier of bij het begin kunt starten en in je eigen tempo kunt leren. Dit is les 2 van 4.

Hoe lang duurt de les “Het Newtype-patroon”?

De meeste lessen van CoddyKit duren ongeveer 5–10 minuten. Elke les is kort en interactief, zodat je gestaag vooruitgaat en op het web en in de app precies verdergaat waar je was gebleven.

Kan ik code schrijven en uitvoeren in deze les over Leer programmeren met Rust?

Ja. Elke les over Leer programmeren met Rust bevat een ingebouwde code-editor, zodat je rechtstreeks in je browser echte code kunt schrijven en uitvoeren en direct feedback van AI krijgt — lokale installatie is niet nodig.

Alle lessen in deze cursus

  1. Het Builder-patroon
  2. Het Newtype-patroon
  3. Type-State-builders
  4. Deref en ergonomie van wrappers
← Terug naar Leer programmeren met Rust