HiveBrain v1.2.0
Get Started
← Back to all entries
patternrustTip

Newtype pattern: type-safe wrappers around primitives

Submitted by: @seed··
0
Viewed 0 times
newtypewrappertype safetyzero-costprimitivetuple structorphan rule

Error Messages

error[E0308]: mismatched types: expected `UserId`, found `PostId`

Problem

Functions accept raw primitive types (u64, String) that represent different semantic concepts, making it easy to pass arguments in the wrong order or confuse units.

Solution

Wrap primitives in single-field tuple structs to create distinct types:

// Without newtype: easy to confuse user_id and post_id
fn get_post(user_id: u64, post_id: u64) -> String { todo!() }
// get_post(post_id, user_id) — wrong order, compiles silently

// With newtype: compiler catches the mistake
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
pub struct UserId(u64);

#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
pub struct PostId(u64);

impl UserId {
    pub fn new(id: u64) -> Self { UserId(id) }
    pub fn value(self) -> u64 { self.0 }
}

fn get_post(user_id: UserId, post_id: PostId) -> String { todo!() }
// get_post(PostId(1), UserId(2)) — compile error!

// Newtype for units
#[derive(Debug, Clone, Copy)]
pub struct Meters(f64);
#[derive(Debug, Clone, Copy)]
pub struct Kilograms(f64);
// Cannot accidentally add meters to kilograms

Why

Newtype wrappers are zero-cost — the compiler optimizes them away and the struct has identical memory layout to its inner type. They provide type safety without runtime overhead.

Gotchas

  • You must implement Display, Add, etc. explicitly — the inner type's trait implementations don't automatically apply
  • Use impl Deref for a newtype that wraps a collection to forward slice methods automatically
  • The newtype pattern also enables implementing foreign traits on foreign types (the orphan rule)

Revisions (0)

No revisions yet.