`Box<T>`
EssentialPrerequisites
Box<T> is the simplest owning heap pointer in Rust. It allocates a single value of type T on the heap and frees that allocation automatically when the Box goes out of scope.
Allocating with Box::new
let b = Box::new(42_i32);
println!("{}", *b); // dereference to read: prints 42
Box::new(value) moves value onto the heap and returns an owning Box<T>. The Box itself is small — one pointer — and lives wherever you declare it: the stack, a struct field, another Box.
To read through a Box, dereference with *. In most contexts Rust dereferences automatically via the Deref trait, so you can use a Box<String> anywhere a String is expected without writing *.
Ownership and Drop
Box<T> implements Drop. When a Box goes out of scope, two things happen in order:
- The contained
Tis dropped (its own cleanup runs first). - The heap allocation is freed.
{
let b = Box::new(String::from("hello"));
println!("{b}");
} // String is dropped, then the heap allocation is freed
The Box owns its contents. Moving the Box moves ownership of the heap allocation. Dropping the Box frees it — no manual free call needed.
Making recursive types representable
The main case that requires Box is recursive inductive types. A bare recursive enum has infinite size:
// error: recursive type `List` has infinite size
enum List {
Nil,
Cons(i32, List),
}
Box<T> has a known, fixed size — one pointer. Wrapping the recursive field in a Box gives the compiler a concrete size:
enum List {
Nil,
Cons(i32, Box<List>),
}
let list = List::Cons(1, Box::new(List::Cons(2, Box::new(List::Nil))));
The list can be as long as memory allows; each Box in the chain always occupies exactly one pointer’s worth of space.
Box<dyn Trait> — runtime polymorphism
Box can hold a trait object: a value whose concrete type is erased at compile time but which is guaranteed to implement a trait:
trait Animal {
fn sound(&self) -> &str;
}
struct Dog;
impl Animal for Dog {
fn sound(&self) -> &str { "woof" }
}
let a: Box<dyn Animal> = Box::new(Dog);
println!("{}", a.sound()); // "woof"
Box<dyn Trait> stores the concrete value on the heap alongside a pointer to its method table. This is how Rust achieves runtime polymorphism when the concrete type cannot be known statically. The full mechanics of trait objects are covered later; the key point here is that Box is the natural container for heap-allocated, type-erased values.
Summary
Box::new(x)movesxto the heap and returns an owning pointer.- When the
Boxis dropped, the heap allocation is freed automatically. Box<T>is the required solution for recursive inductive types.Box<dyn Trait>enables runtime polymorphism.