Newtype-mønsteret
Pakk inn typer for sikkerhet og tydelighet.
Newtype-mønsteret er en gratis leksjon i Lær Rust-programmering på CoddyKit. Dette er leksjon 2 av 4. Du kan lese valgfritt 3 leksjoner fra denne læringsstien gratis i sin helhet – deretter låser CoddyKit PRO opp alle leksjoner, samt praktisk øving med en innebygd kodeeditor og en AI-veileder som er tilgjengelig døgnet rundt. Den er en del av læringsløpet i Lær Rust-programmering, og fremdriften din synkroniseres mellom nettet og CoddyKit-appen. Kurset i Lær Rust-programmering inneholder totalt 4 leksjoner.
Hva er en newtype?
En newtype er en tuppelstruktur med ett felt som pakker inn en eksisterende type for å gi den en egen identitet. struct Meters(f64) er en helt ny type selv om den inneholder en vanlig f64.
Innpakningen har ingen kjøretidskostnad, men lar kompilatoren håndheve en betydning som en rå primitivtype ikke kan håndheve.
struct Meters(f64);
struct Seconds(f64);Forhindre forveksling av enheter
Rå primitivtyper er lette å forveksle. Hvis både avstand og tid er f64, er det ingenting som hindrer Dem i å bytte om på dem i et kall.
Ved å pakke hver av dem inn i sin egen newtype blir slike feil kompilatorfeil i stedet for stille feil.
fn speed(d: Meters, t: Seconds) -> f64 {
d.0 / t.0
}
// speed(Seconds(2.0), Meters(10.0)) -> compile errorFå tilgang til den indre verdien
De får tilgang til den innpakkede verdien gjennom tuppelindeksen .0. Mange newtypes tilbyr også en metode eller implementerer From for praktiske konverteringer.
struct UserId(u64);
impl UserId {
fn value(&self) -> u64 { self.0 }
}
fn main() {
let id = UserId(42);
println!("id = {}", id.value());
}Innkapsle invariants
Gjør det indre feltet privat, og valider det i en konstruktør. Da er alle verdier av newtype-en garantert gyldige, slik at kode lenger nede i programmet aldri trenger å kontrollere dem på nytt.
pub struct Email(String);
impl Email {
pub fn new(s: &str) -> Option<Email> {
if s.contains('@') {
Some(Email(s.to_string()))
} else {
None
}
}
}Orphan-regelen
Rust forbyr implementering av en fremmed trait for en fremmed type. De kan ikke skrive impl Display for Vec<T> fordi De verken eier trait-en eller typen.
Denne regelen sørger for at trait-sammenhengen er konsistent på tvers av crate-er, men kan hindre nyttige implementeringer.
Newtypes omgår orphan-regelen
Fordi newtype-en er definert i cratet Deres, eier De nå en lokal type og kan implementere hvilket som helst trait for den. Dette er den vanlige omveien rundt orphan-regelen.
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(", "))
}
}En kjørbar wrapper med Display
Her tas wrapperen fra forrige scene i bruk. Vi eier Wrapper, så det er tillatt å implementere Display for den, og programmet skriver ut den sammenføyde listen.
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);
}Begrense API-overflaten
Ved å pakke inn en kraftig type kan De eksponere bare et trygt delsett. En NonEmptyVec kan skjule muterende metoder som ellers kunne gjort den tom, og dermed bevare invarianten.
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]
}
}Abstraksjon uten kostnad
En newtype med ett felt har samme minneoppsett som verdien den pakker inn. Kompilatoren optimaliserer wrapperen bort, så sikkerheten her er faktisk kostnadsfri under kjøring.
Ved å legge til #[repr(transparent)] garanteres identisk minneoppsett, noe som er viktig for FFI.
#[repr(transparent)]
struct Celsius(f64);Derivere traits på newtypes
Newtypes deriverer ofte standardtraits slik at de oppfører seg som den indre verdien der det er hensiktsmessig. Derivering gjør dem praktiske for nøkler, sammenligninger og feilsøkingsutskrift.
#[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 kontra typealias
Ikke forveksle en newtype med et typealias. type Meters = f64 er bare et navn; det er fortsatt en f64 og gir ingen ekstra sikkerhet.
En newtype, struct Meters(f64), er en virkelig separat type som kompilatoren kan holde atskilt.
type Km = f64; // alias: interchangeable with f64
struct Mi(f64); // newtype: distinct from f64Kort kontroll
Avgjør hvorfor en newtype er nyttig der et typealias ikke er det.
Oppsummering
Newtype-mønsteret pakker inn en eksisterende type i en tuple struct med ett felt for å gi den en separat identitet uten kjøretidskostnad. Det hindrer sammenblanding av verdier, kapsler inn invariants bak et privat felt og omgår orphan-regelen slik at De kan implementere fremmede traits.
I motsetning til et typealias er en newtype en ekte, separat type.
Lær deg Rust med en AI-veileder – gratis
Skriv og kjør ekte kode i nettleseren, få umiddelbar hjelp fra en AI-veileder som er tilgjengelig døgnet rundt, og fortsett der du slapp – på nettet eller i appen.
- Kurs
- 39
- Leksjoner
- 144
Ofte stilte spørsmål
Er leksjonen «Newtype-mønsteret» gratis?
Ja – du kan lese valgfritt 3 av leksjonene i læringsstien Lær Rust-programmering, inkludert «Newtype-mønsteret», gratis i sin helhet her på nettet. Deretter låser CoddyKit PRO opp alle leksjoner, samt interaktiv øving med en innebygd kodeeditor og en AI-veileder som er tilgjengelig døgnet rundt. Kurset i Lær Rust-programmering inneholder totalt 4 leksjoner.
Hva lærer jeg i «Newtype-mønsteret»?
Pakk inn typer for sikkerhet og tydelighet. Du øver på Lær Rust-programmering med praktisk kode som du kjører direkte i nettleseren, mens en AI-veileder som er tilgjengelig døgnet rundt, svarer på spørsmålene dine mens du jobber deg gjennom leksjonen.
Trenger jeg erfaring for å begynne med Lær Rust-programmering?
Ingen tidligere erfaring er nødvendig. Lær Rust-programmering på CoddyKit er lagt opp for både nybegynnere og viderekomne, så De kan begynne her eller helt fra start og lære i Deres eget tempo. Dette er leksjon 2 av 4.
Hvor lang tid tar leksjonen «Newtype-mønsteret»?
De fleste CoddyKit-leksjoner tar omtrent 5–10 minutter. Hver leksjon er kort og interaktiv, slik at De gjør jevne fremskritt og kan fortsette akkurat der De slapp – både på nettet og i appen.
Kan jeg skrive og kjøre kode i denne Lær Rust-programmering-leksjonen?
Ja. Alle Lær Rust-programmering-leksjoner har en innebygd kodeeditor, slik at De kan skrive og kjøre ekte kode direkte i nettleseren og få umiddelbar tilbakemelding fra AI – uten lokal konfigurering.