0Pricing
Learn Rust Coding · Leçon

Le patron Newtype

Enveloppez les types pour gagner en sécurité et en clarté.

Le patron Newtype est une leçon Learn Rust Coding gratuite sur CoddyKit. Ceci est la leçon 2 sur 4. Tu peux lire la leçon complète ci-dessous gratuitement — puis la pratiquer en direct dans le navigateur avec un éditeur de code intégré et un tuteur IA 24/7. Elle fait partie du parcours d'apprentissage Learn Rust Coding, et ta progression se synchronise sur le web et l'application CoddyKit. Le cours Learn Rust Coding comprend 4 leçons au total.

Certaines parties de cette leçon n'ont pas encore été traduites et s'affichent en anglais.

What Is a Newtype?

A newtype is a single-field tuple struct that wraps an existing type to give it a distinct identity. struct Meters(f64) is a brand new type even though it holds a plain f64.

The wrapper has zero runtime cost but lets the compiler enforce meaning that a raw primitive cannot.

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

Preventing Unit Mix-Ups

Raw primitives are easy to confuse. If both a distance and a time are f64, nothing stops you swapping them in a call.

Wrapping each in its own newtype makes such mistakes a compile error instead of a silent bug.

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

Accessing the Inner Value

You reach the wrapped value through tuple index .0. Many newtypes also expose a method or implement From for ergonomic conversions.

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

Encapsulating Invariants

Make the inner field private and validate in a constructor. Then any value of the newtype is guaranteed valid, so downstream code never re-checks.

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

The Orphan Rule

Rust forbids implementing a foreign trait for a foreign type. You cannot write impl Display for Vec<T> because you own neither the trait nor the type.

This rule keeps trait coherence sound across crates, but it can block useful impls.

Newtypes Bypass the Orphan Rule

Because the newtype is defined in your crate, you now own a local type and may implement any trait for it. This is the standard workaround for the orphan rule.

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

A Runnable Wrapper Display

Here the wrapper from the previous scene is put to work. We own Wrapper, so implementing Display for it is allowed and the program prints the joined list.

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

Restricting the API Surface

Wrapping a powerful type lets you expose only a safe subset. A NonEmptyVec can hide mutating methods that would let it become empty, preserving its 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]
    }
}

Zero-Cost Abstraction

A newtype with one field has the same memory layout as the wrapped value. The compiler optimizes the wrapper away, so safety here is genuinely free at runtime.

Adding #[repr(transparent)] guarantees identical layout, which matters for FFI.

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

Deriving Traits on Newtypes

Newtypes often derive standard traits so they behave like the inner value where appropriate. Deriving keeps them ergonomic for keys, comparisons, and debug output.

#[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

Do not confuse a newtype with a type alias. type Meters = f64 is just a name; it is still an f64 and offers no extra safety.

A newtype struct Meters(f64) is a genuinely distinct type the compiler can keep separate.

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

Quick Check

Decide why a newtype helps where a type alias does not.

Recap

The newtype pattern wraps an existing type in a one-field tuple struct to gain a distinct identity at zero runtime cost. It prevents value mix-ups, encapsulates invariants behind a private field, and sidesteps the orphan rule so you can implement foreign traits.

Unlike a type alias, a newtype is a real, separate type.

Questions Fréquemment Posées

La leçon « Le patron Newtype » est-elle gratuite ?

Oui — le texte complet de « Le patron Newtype » est gratuit à lire ici sur le web. Pour la pratiquer de manière interactive (un éditeur de code intégré et un tuteur IA 24/7) et déverrouiller le reste du cours Learn Rust Coding, passe à CoddyKit PRO. Le cours Learn Rust Coding comprend 4 leçons au total.

Qu'est-ce que j'apprendrai dans « Le patron Newtype » ?

Enveloppez les types pour gagner en sécurité et en clarté. Tu pratiques Learn Rust Coding avec du code pratique que tu exécutes directement dans le navigateur, et un tuteur IA 24/7 répond à tes questions au fur et à mesure que tu avances dans la leçon.

Dois-je avoir de l'expérience pour commencer Learn Rust Coding ?

Aucune expérience préalable n'est requise. Learn Rust Coding sur CoddyKit est structuré pour les débutants jusqu'aux apprenants avancés, donc tu peux commencer ici ou depuis le début et avancer à ton rythme. Ceci est la leçon 2 sur 4.

Combien de temps prend la leçon « Le patron Newtype » ?

La plupart des leçons CoddyKit prennent environ 5–10 minutes. Chacune est courte et interactive, tu progresses régulièrement et tu repiques exactement où tu t'es arrêté sur le web et l'app.

Peux-tu écrire et exécuter du code dans cette leçon Learn Rust Coding ?

Oui. Chaque leçon Learn Rust Coding inclut un éditeur de code intégré, tu écris et exécutes du vrai code directement dans ton navigateur et tu reçois des retours IA instantanés — aucune configuration locale requise.

Toutes les leçons de ce cours

  1. Le patron Builder
  2. Le patron Newtype
  3. Builders fondés sur l’état du type
  4. Ergonomie de Deref et des enveloppes
← Retour à Learn Rust Coding