🎓 A1Learner
🔍

Rust Your Own Smart Pointer

A smart pointer of your own is a struct that implements the Deref trait. The real Box stores its value on the heap.

A pointer shell: one field

A tuple struct with one field makes a good pointer shell. On its own it cannot be dereferenced: *mybox fails with error E0614 (checked).

struct MyBox<T>(T);

impl<T> MyBox<T> {
    fn new(x: T) -> MyBox<T> { MyBox(x) }
}

Deref: say what it points at

Target names what the pointer points at. When you write *y, Rust really runs *(y.deref()) — one deref call, then a plain dereference.

impl<T> Deref for MyBox<T> {
    type Target = T;
    fn deref(&self) -> &Self::Target { &self.0 }
}

Read and write through it

A DerefMut impl — fn deref_mut(&mut self) -> &mut Self::Target { &mut self.0 } — is what lets *n = 6 write through the pointer.

let mut n = MyBox::new(5);
println!("n = {}", *n);
*n = 6;
println!("n = {}", *n);

Coercion walks through MyBox too

hello wants a &str. We pass &m, a &MyBox<String>, and coercion walks the chain: MyBox, then String, then str.

let m = MyBox::new(String::from("Rust"));
hello(&m);

Example

use std::ops::{Deref, DerefMut};
struct MyBox<T>(T);
impl<T> MyBox<T> { fn new(x: T) -> MyBox<T> { MyBox(x) } }
impl<T> Deref for MyBox<T> { type Target = T; fn deref(&self) -> &Self::Target { &self.0 } }
impl<T> DerefMut for MyBox<T> { fn deref_mut(&mut self) -> &mut Self::Target { &mut self.0 } }
fn hello(name: &str) { println!("Hello, {name}!"); }
fn main() {
    let mut n = MyBox::new(5);
    println!("n = {}", *n);
    *n = 6;
    println!("n = {}", *n);
    let m = MyBox::new(String::from("Rust"));
    hello(&m);
}

Key points

  • deref returns a reference (&self.0), never the value itself: returning the value would move it out of the pointer
  • A custom pointer is an ordinary struct: Deref is the trait that makes it act like a pointer.
  • Rust resolves every deref step while compiling — your pointer is exactly as fast as a plain reference.
  • MyBox stores its value inline, only to keep the focus on the Deref trait.

In this example, MyBox is a tuple struct holding one value. The Deref impl says its Target is T and returns &self.0, a reference to the held value, so *n reads the 5. The DerefMut impl returns &mut self.0, so *n = 6 can write through the pointer and the second line prints 6. Finally, hello wants a &str. We pass &m, a &MyBox<String>. Deref coercion walks the chain — MyBox to String to str. So the call works and prints Hello, Rust!.

Note

None of this costs anything at run time.

Try it Yourself

Edit the code, then press Run.

Running is simulated · Rust Playground

Exercise

Why does the deref method return a reference instead of the value itself?