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)