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:
- At the current type
T, try by-value receivers (T) and autoref receivers (&T,&mut T). - Try unsized coercions if
Tis a fixed-size array[U; N](coercing to[U]). - If no method matches on
TandT: Deref<Target = U>, dereference once toUand 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.