Guide

Box

Box<T> is the simplest smart pointer. It puts a value on the heap and keeps a small pointer on the stack.

Box<T>

Box::new(x) moves x onto the heap. The box owns that value, just like a String owns its text. A box moves on assignment, and when the box goes out of scope, the heap value is freed.

let b = Box::new(5);let c = b;          // the box moves to cprintln!("{c}");    // 5

Dereferencing a Box

Use *b to get the value inside. Methods work through the box on their own, so b.len() just works.

let mut b = Box::new(10);*b += 1;            // change the value insidelet s = Box::new(String::from("hey"));println!("{} {}", b, s.len()); // 11 3

Recursive types

A type that holds itself directly would have infinite size. Rust can't lay it out and reports E0072. A Box has a fixed size (one pointer), so it breaks the loop.

enum List {    Cons(i32, Box<List>),    Nil,}

Wrapping in Option alone does not help, because Option<List> still holds a whole List.

Box<dyn Trait>

Different types can have different sizes, so a Vec can't hold them directly. Box<dyn Trait> holds any type that implements the trait, and every box has the same size.

trait Speak { fn say(&self) -> &str; }struct Dog;struct Cat;impl Speak for Dog { fn say(&self) -> &str { "woof" } }impl Speak for Cat { fn say(&self) -> &str { "meow" } }let pets: Vec<Box<dyn Speak>> =    vec![Box::new(Dog), Box::new(Cat)];println!("{}", pets[1].say()); // meow

Each box calls the say of the type inside it.

Remember

  • Box::new puts a value on the heap; the box is its one owner.
  • *b reads the value; methods work through the box.
  • E0072 means a type contains itself; add a Box.
  • Box<dyn Trait> lets one list hold many types.