DEV Community

Subesh Yadav
Subesh Yadav

Posted on

Day 28 of #100DaysOfRust: Smart Pointers and Deref Coercion

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);
}
Enter fullscreen mode Exit fullscreen mode

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);
}
Enter fullscreen mode Exit fullscreen mode

🛠 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)
    }
}
Enter fullscreen mode Exit fullscreen mode

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
    }
}
Enter fullscreen mode Exit fullscreen mode

Now *y works just like with Box<T>.

Behind the scenes:

*(y.deref())
Enter fullscreen mode Exit fullscreen mode

This happens automatically whenever we use *.


🔄 Implicit Deref Coercions

Deref coercion allows automatic conversion between references:

  • From &T to &U when T: Deref<Target=U>
  • From &mut T to &mut U when T: DerefMut<Target=U>
  • From &mut T to &U when T: 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
}
Enter fullscreen mode Exit fullscreen mode

Without coercion, we’d need:

hello(&(*m)[..]);
Enter fullscreen mode Exit fullscreen mode

Much harder to read!


🔐 Deref and Mutability

  • &T → &U works with Deref.
  • &mut T → &mut U works with DerefMut.
  • &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 implement Deref 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)