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

Subesh Yadav @subesh_yadav

About: Full-stack developer (React + Node.js) | SDE II Dreaming in TypeScript, compiling in Rust 🧠💻 Building in public → #100DaysOfRust Web + Systems + Performance

Location:
Varanasi, Uttar Pradesh, India
Joined:
Jul 9, 2025

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

Publish Date: Sep 17 '25
0 0

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

Comments 0 total

    Add comment