Type System Fundamentals

Type Coercions

A type coercion is an implicit, lossless type conversion that the compiler performs automatically at specific coercion sites (such as let bindings with explicit types, function arguments, struct field initializers, and return expressions). Unlike C, Rust never performs implicit numeric coercions (i32 to i64 or f64).

The Six Implicit Coercions in Safe Rust

Coercion Kind Source Type $\rightarrow$ Target Type Example
1. Deref coercion &T $\rightarrow$ &U (where T: Deref<Target = U>) &String $\rightarrow$ &str, &Vec<T> $\rightarrow$ &[T], &Box<T> $\rightarrow$ &T
2. Unsize coercion &[T; N] $\rightarrow$ &[T], or &Concrete $\rightarrow$ &dyn Trait &[1, 2, 3] $\rightarrow$ &[i32], Box<Circle> $\rightarrow$ Box<dyn Draw>
3. Mutability weakening &mut T $\rightarrow$ &T, or *mut T $\rightarrow$ *const T Passing &mut buf to a function expecting &buf
4. Reference-to-raw-pointer &T $\rightarrow$ *const T, or &mut T $\rightarrow$ *mut T Passing &val to a *const T parameter
5. Non-capturing closure / fn item to fn pointer fn foo() or |x| x + 1 $\rightarrow$ fn(i32) -> i32 Storing closures/functions in a Vec<fn(i32) -> i32>
6. Never type (!) coercion ! $\rightarrow$ any type T return, break, continue, panic!, or loop {} inside an if / else arm

Demonstrating the Implicit Coercions Together

fn accept_slice(s: &[i32]) -> i32 {
    s.iter().sum()
}

fn main() {
    // 1. Unsize coercion: `&[i32; 3]` -> `&[i32]`
    let arr = [10, 20, 30];
    println!("Array -> slice sum: {}", accept_slice(&arr));

    // 2. Mutability weakening + Deref coercion: `&mut Vec<i32>` -> `&[i32]`
    let mut vec = vec![5, 15];
    println!("&mut Vec -> slice sum: {}", accept_slice(&mut vec));

    // 3. Non-capturing closures coercing to a common function pointer `fn(i32) -> i32`:
    let ops: [fn(i32) -> i32; 2] = [|x| x + 1, |x| x * 10];
    println!("ops[0](4) = {}, ops[1](4) = {}", ops[0](4), ops[1](4));

    // 4. Never type `!` coercing to `i32`:
    let flag = true;
    let val: i32 = if flag { 42 } else { panic!("unreachable") };
    println!("val = {val}");
}
Array -> slice sum: 60
&mut Vec -> slice sum: 20
ops[0](4) = 5, ops[1](4) = 40
val = 42

Implicit Coercion vs. Explicit as Cast vs. From / Into

Mechanism Syntax Applies To Can Lose Information?
Implicit coercion Automatic at coercion sites References, pointers, unsizing, fn pointers, ! No
From / Into u64::from(x_u32) / x.into() Value-preserving conversions between distinct types No (infallible and lossless)
TryFrom / TryInto u8::try_from(x_i32) Narrowing or validated conversions Returns Err if out of range
as cast x as u8, ptr as usize Primitive scalars, raw pointers, C-like enums Yes (truncates integers, saturates float-to-int)