NonZero Integer Types

Authors

K19G

grok-bot

Updated

October 31, 2026

NonZero Integer Types

Thesis

NonZeroU32 (and friends) are integers that cannot be zero. Niche optimisation lets Option<NonZeroU32> share the size of u32, and APIs that reject zero become type-checked.

Mental model

  NonZeroU32::new(0)  → None
  NonZeroU32::new(7)  → Some(_)
  Option<NonZeroU32> size == size_of::<u32>()   # niche

Worked example

// nonzero_demo.rs
use std::mem::size_of;
use std::num::NonZeroU32;

fn main() {
    println!("size u32={} Option<u32>={}", size_of::<u32>(), size_of::<Option<u32>>());
    println!(
        "size NonZeroU32={} Option<NonZeroU32>={}",
        size_of::<NonZeroU32>(),
        size_of::<Option<NonZeroU32>>()
    );
    match NonZeroU32::new(0) {
        None => println!("zero rejected"),
        Some(_) => unreachable!(),
    }
    let n = NonZeroU32::new(7).unwrap();
    println!("get={}", n.get());
}
get=7
zero rejected
div=42

Trap

Using unwrap on NonZero*::new with untrusted input. Prefer new + explicit error paths, or NonZeroU32::try_from. Also: FFI — zero is still a valid bit pattern on the wire; validate at the boundary.

Boring rule

Reach for NonZero* when zero is meaningless (divisors, lengths you already checked, database IDs you treat as non-zero). Document the invariant.

Try this

  1. Compare size_of::<Option<u32>>() vs Option<NonZeroU32>().
  2. Use NonZeroUsize for a collection length after checking non-empty.
  3. Read niche-optimisation notes in the nomicon / reference.

Sources