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
&T
to&U
whenT: Deref<Target=U>
- From
&mut T
to&mut U
whenT: DerefMut<Target=U>
- From
&mut T
to&U
whenT: 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 → &U
works withDeref
. -
&mut T → &mut U
works withDerefMut
. -
&mut T → &U
is also allowed. - ❌ But
&T → &mut U
is 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 implementDeref
to 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)