Associated Types and Advanced Traits

The Deref Coercion Mechanism

Deref coercion is a compile-time conversion performed automatically by the Rust compiler that turns a reference to a type implementing Deref (or DerefMut) into a reference to its Deref::Target type.

How Deref Coercion Works

When an expression of type &T or &mut T is passed to a function parameter, assigned to a typed binding, or used as the receiver of a method call (.), the compiler repeatedly invokes Deref::deref (or DerefMut::deref_mut) until the reference matches the required target type:

&Box<String>
   │  Deref::deref on Box<String> (Target = String)
   ▼
&String
   │  Deref::deref on String (Target = str)
   ▼
&str

Because each step resolves at compile time, deref coercion has zero runtime overhead beyond the underlying pointer read in Deref::deref.

fn first_word(text: &str) -> &str {
    text.split_whitespace().next().unwrap_or("")
}

fn main() {
    let boxed_string: Box<String> = Box::new(String::from("zero overhead abstractions"));

    // Implicit deref chain: &Box<String> -> &String -> &str
    let word = first_word(&boxed_string);
    println!("First word: {word}");
}
First word: zero

The Three Mutability Coercion Rules

Rust permits deref coercion across three mutability combinations:

Source Reference Target Reference Required Trait Implementation
&T &U T: Deref<Target = U>
&mut T &mut U T: DerefMut<Target = U>
&mut T &U T: Deref<Target = U> (downgrades &mut to &)

Coercing &T to &mut U is never allowed, because obtaining a mutable reference from a shared reference would violate Rust's aliasing rules.

Method Resolution Order with Deref Coercion

When you call value.method(), the compiler searches for a matching receiver type along the deref chain in a deterministic order:

  1. At the current type T, try by-value receivers (T) and autoref receivers (&T, &mut T).
  2. Try unsized coercions if T is a fixed-size array [U; N] (coercing to [U]).
  3. If no method matches on T and T: Deref<Target = U>, dereference once to U and repeat from step 1.
use std::ops::Deref;

struct Wrapper(String);

impl Deref for Wrapper {
    type Target = String;

    fn deref(&self) -> &Self::Target {
        &self.0
    }
}

fn main() {
    let w = Wrapper(String::from("  rust  "));

    // `trim()` is defined on `str`.
    // Resolution path: Wrapper -> String (via Deref) -> str (via Deref) -> str::trim(&self)
    println!("Trimmed: '{}'", w.trim());
}
Trimmed: 'rust'

Where Deref Coercion Does Not Apply

Deref coercion applies only to concrete reference arguments and method receivers. It does not satisfy generic trait bounds—passing &String to a generic function fn process<T: SomeTraitOnStr>(x: &T) will not coerce T from String to str unless you pass x.as_str() explicitly.