Guide

Drop and Deref

Smart pointers like Box and Rc are built on two traits: Drop and Deref. You can use them on your own types too.

The Drop trait

Drop lets you run code when a value goes away. Write one method, fn drop(&mut self).

struct Guard;impl Drop for Guard {    fn drop(&mut self) {        println!("bye");    }}

You never call x.drop() yourself (error E0040). To drop a value early, call drop(x).

Drop order

Local variables are dropped at the end of their scope, in reverse order of creation. The last one made is the first one dropped. This is safe: a value made later may borrow one made earlier, so the later one must go first.

struct Name(char);impl Drop for Name {    fn drop(&mut self) {        println!("drop {}", self.0);    }}fn main() {    let _a = Name('a');    let _b = Name('b');} // prints "drop b", then "drop a"

Shadowing does not drop the old value early; it still waits for the end of the scope. But let _ = value; drops the value right away, because nothing keeps it.

The Deref trait

Deref makes * work on your own type. You say what it points to with type Target, and return a reference to it.

use std::ops::Deref;struct MyBox<T>(T);impl<T> Deref for MyBox<T> {    type Target = T;    fn deref(&self) -> &T { &self.0 }}fn main() {    let b = MyBox(5);    println!("{}", *b); // 5}

Now *b means *(b.deref()).

Deref coercion

String implements Deref with Target = str. So when a function wants &str and you pass &String, Rust calls deref for you. It keeps going as far as needed: &Box<String> becomes &String, then &str.

fn hello(name: &str) {    println!("hi {name}");}fn main() {    let b = Box::new(String::from("Ann"));    hello(&b); // hi Ann}

It only goes one way: a &str never turns into a &String.

Remember

  • Drop runs your code when a value goes away; use drop(x) to do it early.
  • Locals drop in reverse order of creation.
  • Deref with type Target makes * work.
  • Deref coercion turns &String into &str for you.