Essential Standard Traits
Deref and DerefMut
The Deref and DerefMut traits in std::ops overload the unary dereference operator (*value) for smart pointers and owning wrapper types, and power the compiler's implicit deref coercion mechanism.
Trait Definitions
pub trait Deref {
type Target: ?Sized;
fn deref(&self) -> &Self::Target;
}
pub trait DerefMut: Deref {
fn deref_mut(&mut self) -> &mut Self::Target;
}
When *x is evaluated on an immutable smart pointer, the compiler rewrites it to *(Deref::deref(&x)). When *x is evaluated in a mutable context, the compiler rewrites it to *(DerefMut::deref_mut(&mut x)).
Standard Library Deref Implementations
| Smart Pointer / Owner | Deref::Target |
Effect of Deref Coercion |
|---|---|---|
Box<T> |
T |
&Box<T> coerces to &T; &mut Box<T> coerces to &mut T |
Rc<T> / Arc<T> |
T |
&Rc<T> and &Arc<T> coerce to &T (no DerefMut because ownership is shared) |
String |
str |
&String coerces to &str, exposing all str methods on String |
Vec<T> |
[T] |
&Vec<T> coerces to &[T], exposing all slice methods on Vec<T> |
MutexGuard<'_, T> |
T |
Guard acts as a smart pointer to the protected value T |
Implementing Deref and DerefMut on a Smart Pointer
use std::ops::{Deref, DerefMut};
struct TrackedBox<T> {
value: T,
mutations: usize,
}
impl<T> TrackedBox<T> {
fn new(value: T) -> Self {
Self {
value,
mutations: 0,
}
}
}
impl<T> Deref for TrackedBox<T> {
type Target = T;
fn deref(&self) -> &Self::Target {
&self.value
}
}
impl<T> DerefMut for TrackedBox<T> {
fn deref_mut(&mut self) -> &mut Self::Target {
self.mutations += 1;
&mut self.value
}
}
fn greet(name: &str) {
println!("Hello, {name}!");
}
fn main() {
let mut tracked = TrackedBox::new(String::from("Rust"));
tracked.push_str(" 2024"); // Uses DerefMut<Target = String>
// Deref coercion chain: &TrackedBox<String> -> &String -> &str
greet(&tracked);
println!("Mutations recorded: {}", tracked.mutations);
}
Hello, Rust 2024!
Mutations recorded: 1
Implicit Deref Coercion Rules
When passing a reference or calling a method via the . operator, the compiler automatically applies Deref::deref or DerefMut::deref_mut as many times as needed to match the expected type:
&Tto&UwhenT: Deref<Target = U>&mut Tto&mut UwhenT: DerefMut<Target = U>&mut Tto&UwhenT: Deref<Target = U>(mutable reference weakens to shared reference; the reverse is never permitted)
Only implement Deref for smart pointer or transparent wrapper types—never to simulate class inheritance between unrelated domain structs.