Deref & Deref Coercion
Deref maps smart pointer to inner reference. Deref coercion converts &T to &U when T: Deref<Target=U> at call sites.
Recipe
use std::ops::Deref;
struct MyString(String);
impl Deref for MyString {
type Target = str;
fn deref(&self) -> &str { &self.0 }
}
fn print_len(s: &str) { println!("{}", s.len()); }
fn main() {
let s = MyString("hello".into());
print_len(&s); // coercion &MyString -> &str
}When to reach for this: Newtype wrappers and smart pointers acting like inner type.
Working Example
fn main() {
let s = String::from("rust");
let len = str_len(&s);
println!("{len}");
}
fn str_len(s: &str) -> usize { s.len() }What this demonstrates:
&Stringcoerces to&strviaDerefBox<T>,Rc<T>similarly coerce whenT: Deref- Automatic at function arguments
Deep Dive
Deref coercion chain limited to avoid infinite recursion. DerefMut for mutable coercion.
Gotchas
- Deref returning wrong lifetime - Compile errors. Fix: Match inner field lifetime.
- Over-Deref in API - Hidden allocations if
Derefclones. Fix: implDerefto inner ref only. - Deref polymorphism abuse - Not inheritance. Fix: Prefer traits for behavior sharing.
- Ambiguous coercion - Multiple Deref paths rare.
- Manual * deref -
*boxexplicit deref.
Alternatives
| Alternative | Use When | Don't Use When |
|---|---|---|
AsRef trait | Explicit conversion intent | Deref ergonomics wanted |
.as_str() method | Clear conversion | Coercion magic ok |
| Borrow trait | Hash map keys | General param coercion |
FAQs
String to str?
Classic coercion example.Vec to slice?
&Vec<T> -> &[T].Box?
&Box<T> -> &T if T: ?.multiple deref?
Limited chain.DerefMut?
Mut coercion Box to inner mut.unsized coercion?
Part of DST stories.custom smart pointer?
Impl Deref + Drop.pin deref?
Pin projects to inner.lint?
avoid deref in some style guides - rare.vs AsRef?
AsRef explicit method call.Related
Stack versions: This page was written for Rust 1.97.0 (edition 2024), Tokio 1.x, Axum 0.8, serde 1.0, sqlx 0.8, clap 4, and Polars 0.46+.