Today’s learning was all about treating smart pointers like regular references by implementing the Deref trait, exploring deref coercion, and understanding how it interacts with mutability.
📌 Following References to Values
A regular reference (&T) points to a value stored elsewhere. To access the value, we use the dereference operator *:
fn main() {
let x = 5;
let y = &x;
assert_eq!(5, x);
assert_eq!(5, *y);
}
Here *y follows the reference to get the value 5. Without *, the comparison won’t compile because {integer} and &{integer} are different types.
📦 Using Box Like a Reference
Smart pointers like Box<T> behave similarly to references when dereferenced:
fn main() {
let x = 5;
let y = Box::new(x);
assert_eq!(5, x);
assert_eq!(5, *y);
}
🛠 Defining Our Own Smart Pointer
We can define our own smart pointer MyBox<T>:
struct MyBox<T>(T);
impl<T> MyBox<T> {
fn new(x: T) -> MyBox<T> {
MyBox(x)
}
}
But trying to dereference *y will fail until we implement the Deref trait.
🔗 Implementing the Deref Trait
To enable dereferencing:
use std::ops::Deref;
impl<T> Deref for MyBox<T> {
type Target = T;
fn deref(&self) -> &Self::Target {
&self.0
}
}
Now *y works just like with Box<T>.
Behind the scenes:
*(y.deref())
This happens automatically whenever we use *.
🔄 Implicit Deref Coercions
Deref coercion allows automatic conversion between references:
- From
&Tto&UwhenT: Deref<Target=U> - From
&mut Tto&mut UwhenT: DerefMut<Target=U> - From
&mut Tto&UwhenT: Deref<Target=U>
Example with MyBox<String>:
fn hello(name: &str) {
println!("Hello, {name}!");
}
fn main() {
let m = MyBox::new(String::from("Rust"));
hello(&m); // Works because of deref coercion
}
Without coercion, we’d need:
hello(&(*m)[..]);
Much harder to read!
🔐 Deref and Mutability
-
&T → &Uworks withDeref. -
&mut T → &mut Uworks withDerefMut. -
&mut T → &Uis also allowed. - ❌ But
&T → &mut Uis not allowed, because it could break Rust’s borrowing rules.
This ensures safety and prevents undefined behavior.
🧠 Summary
- Regular references require
*to access the value. -
Box<T>and custom smart pointers can implementDerefto behave like references. - Deref coercion simplifies function calls by automatically converting types.
- Mutability rules ensure safety: mutable → immutable works, but immutable → mutable does not.
Rust’s deref system is a zero-cost abstraction: all conversions happen at compile time with no runtime cost.
🚀 That’s all for Day 28! Tomorrow, I’ll continue exploring more about **smart pointers and their advanced use
Top comments (0)