Type System Fundamentals

Primitive and Composite Types

Every type in Rust is either a primitive type built directly into the language compiler or a composite type constructed by combining existing types.

Taxonomy of Rust's Type Hierarchy

Rust Types
  ├── 1. Primitive Types (Built into the compiler)
  │        ├── Scalars:    i8..i128, isize, u8..u128, usize, f32, f64, bool, char
  │        ├── Text slice: str (unsized UTF-8 slice)
  │        ├── Unit & !:   () (1 value) and ! (never type, 0 values)
  │        └── Pointers:   &T, &mut T, *const T, *mut T, fn(...) -> R
  │
  └── 2. Composite Types (Built from other types)
           ├── Structural: Tuples `(A, B)`, Arrays `[T; N]`, Slices `[T]`
           └── Nominal:    `struct`, `enum`, `union`, Trait Objects `dyn Trait`

Reference of Built-In Primitive Types

Category Types Size in Memory Notes
Signed Integers i8, i16, i32, i64, i128, isize 1, 2, 4, 8, 16 B, pointer-sized Two's complement representation
Unsigned Integers u8, u16, u32, u64, u128, usize 1, 2, 4, 8, 16 B, pointer-sized usize is used for all slice indices and memory sizes
Floating-Point f32, f64 4 B, 8 B IEEE 754 single and double precision
Boolean bool 1 B (0x00 or 0x01) Niche-optimized (0x02..=0xFF unused)
Unicode Scalar char 4 B Valid Unicode scalar value (0x0000..=0xD7FF, 0xE000..=0x10FFFF)
Unit Type () 0 B (ZST) Returned by expressions with no meaningful value
Never Type ! 0 B (uninhabited) Returned by diverging expressions (panic!, return, loop {})

Structural Composite Types: Tuples, Arrays, and Slices

fn analyze_packet(packet: &[u8; 4]) -> (u8, &[u8]) {
    let version = packet[0];
    let payload: &[u8] = &packet[1..];
    (version, payload)
}

fn main() {
    let raw: [u8; 4] = [1, 0xAA, 0xBB, 0xCC];
    let (ver, body) = analyze_packet(&raw);

    println!("Version: {ver}, body: {body:02X?}");
}
Version: 1, body: [AA, BB, CC]

Even though primitive types (i32, str, [T]) are built into the compiler for layout and code generation, the standard library (core and std) attaches inherent methods and trait implementations directly to them (impl i32 { ... }, impl<T> [T] { ... }) so primitives and composite types share a unified method-call syntax (42_u32.count_ones(), [1, 2, 3].len()).