Newtype-mønstret
Pak typer ind for sikkerhed og tydelighed.
Newtype-mønstret er en gratis Lær at programmere i Rust-lektion på CoddyKit. Dette er lektion 2 af 4. Du kan læse alle 3 lektioner i dette læringsspor gratis i deres fulde længde — derefter låser CoddyKit PRO alle lektioner op samt praktiske øvelser med en indbygget kodeeditor og en AI-underviser døgnet rundt. Den er en del af læringsforløbet i Lær at programmere i Rust, og dine fremskridt synkroniseres på tværs af nettet og CoddyKit-appen. Lær at programmere i Rust-kurset indeholder 4 lektioner i alt.
Hvad er en newtype?
En newtype er en tuppelstruktur med ét felt, som omslutter en eksisterende type for at give den en særskilt identitet. struct Meters(f64) er en helt ny type, selv om den indeholder en almindelig f64.
Omslaget har ingen omkostning under kørsel, men lader compileren håndhæve en betydning, som en rå primitiv type ikke kan.
struct Meters(f64);
struct Seconds(f64);Forebyg sammenblanding af enheder
Rå primitive typer er nemme at forveksle. Hvis både en afstand og en tid er f64, er der intet, der forhindrer dig i at bytte dem om i et kald.
Hvis du omslutter hver af dem i sin egen newtype, bliver sådanne fejl til kompileringsfejl i stedet for skjulte fejl.
fn speed(d: Meters, t: Seconds) -> f64 {
d.0 / t.0
}
// speed(Seconds(2.0), Meters(10.0)) -> compile errorAdgang til den indre værdi
Du får adgang til den omsluttede værdi gennem tuppelindekset .0. Mange newtypes udstiller også en metode eller implementerer From for at gøre konverteringer nemmere.
struct UserId(u64);
impl UserId {
fn value(&self) -> u64 { self.0 }
}
fn main() {
let id = UserId(42);
println!("id = {}", id.value());
}Indkapsling af invarians
Gør det indre felt privat, og validér det i en konstruktør. Derefter er enhver værdi af newtype-typen garanteret at være gyldig, så kode længere nede i programmet ikke behøver at validere den igen.
pub struct Email(String);
impl Email {
pub fn new(s: &str) -> Option<Email> {
if s.contains('@') {
Some(Email(s.to_string()))
} else {
None
}
}
}Forældreløshedsreglen
Rust forbyder at implementere et fremmed trait for en fremmed type. Du kan ikke skrive impl Display for Vec<T>, fordi du hverken ejer traitet eller typen.
Denne regel holder trait-sammenhængen konsistent på tværs af crates, men den kan blokere nyttige implementeringer.
Newtypes omgår forældreløshedsreglen
Fordi newtypen er defineret i din crate, ejer du nu en lokal type og må implementere ethvert trait for den. Det er den almindelige løsning på orphan-reglen.
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 kørbar Wrapper, der kan vises
Her tages wrapperen fra den forrige scene i brug. Vi ejer Wrapper, så det er tilladt at implementere Display for den, og programmet udskriver den sammenkædede liste.
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);
}Begrænsning af API-overfladen
Ved at indpakke en kraftfuld type kan du kun eksponere en sikker delmængde. En NonEmptyVec kan skjule ændringsmetoder, som ellers ville gøre den tom, og dermed bevare sin invariant.
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 uden omkostninger
En newtype med ét felt har samme hukommelseslayout som den indpakkede værdi. Compileren optimerer wrapperen væk, så sikkerheden her reelt er gratis under kørsel.
Tilføjelse af #[repr(transparent)] garanterer et identisk layout, hvilket er vigtigt for FFI.
#[repr(transparent)]
struct Celsius(f64);Afledning af traits på newtypes
Newtypes afleder ofte standardtraits, så de opfører sig som den indre værdi, hvor det er passende. Afledning gør dem nemme at bruge som nøgler, til sammenligninger og til fejlsøgningsoutput.
#[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
Forveksl ikke en newtype med et typealias. type Meters = f64 er blot et navn; det er stadig en f64 og giver ingen ekstra sikkerhed.
En newtype, struct Meters(f64), er en reelt særskilt type, som compileren kan holde adskilt.
type Km = f64; // alias: interchangeable with f64
struct Mi(f64); // newtype: distinct from f64Hurtigt tjek
Find ud af, hvorfor en newtype hjælper, hvor et typealias ikke gør.
Opsummering
Newtype-mønstret pakker en eksisterende type ind i en tuple-struktur med ét felt for at give den en særskilt identitet uden omkostninger under kørsel. Det forhindrer, at værdier forveksles, indkapsler invariants bag et privat felt og omgår orphan-reglen, så du kan implementere fremmede traits.
I modsætning til et typealias er en newtype en reel, separat type.
Lær Rust med en AI-underviser — gratis
Skriv og kør rigtig kode i din browser, få øjeblikkelig hjælp fra en AI-underviser døgnet rundt, og fortsæt, hvor du slap, på web eller i appen.
- Kurser
- 39
- Lektioner
- 144
Ofte stillede spørgsmål
Er lektionen “Newtype-mønstret” gratis?
Ja — alle 3 lektioner i læringssporet Lær at programmere i Rust, inklusive “Newtype-mønstret”, kan læses gratis i deres fulde længde her på webstedet. Derefter låser CoddyKit PRO alle lektioner op samt interaktive øvelser med en indbygget kodeeditor og en AI-underviser døgnet rundt. Lær at programmere i Rust-kurset indeholder 4 lektioner i alt.
Hvad lærer jeg i “Newtype-mønstret”?
Pak typer ind for sikkerhed og tydelighed. Du øver dig i Lær at programmere i Rust med praktisk kode, som du kører direkte i browseren, og en AI-vejleder døgnet rundt besvarer dine spørgsmål, mens du arbejder dig gennem lektionen.
Skal jeg have erfaring for at begynde på Lær at programmere i Rust?
Der kræves ingen tidligere erfaring. Lær at programmere i Rust på CoddyKit er tilrettelagt for både begyndere og øvede, så du kan starte her eller fra begyndelsen og lære i dit eget tempo. Dette er lektion 2 af 4.
Hvor lang tid tager lektionen “Newtype-mønstret”?
De fleste CoddyKit-lektioner tager cirka 5–10 minutter. Hver lektion er kort og interaktiv, så du gør løbende fremskridt og kan fortsætte, hvor du slap – på både web og app.
Kan jeg skrive og køre kode i denne Lær at programmere i Rust-lektion?
Ja. Alle Lær at programmere i Rust-lektioner har en indbygget kodeeditor, så du kan skrive og køre rigtig kode direkte i din browser og få øjeblikkelig feedback fra AI – uden lokal opsætning.