Introduction
Box is the simplest smart pointer in Rust — it allocates a value on the heap and provides single ownership semantics. Despite its simplicity, Box is essential for recursive types, large data transfers, and trait objects.
Key Concepts
- Box<T>: A smart pointer that allocates T on the heap with a single owner. When the Box is dropped, the heap memory is freed.
- Deref coercion: Box implements
Deref, so a&Box<T>automatically coerces to&Tin function calls. - Recursive type: A type that contains itself, which has infinite size unless indirected through a pointer like Box.
Real World Context
You use Box every time you build a tree, linked list, or any recursive data structure. It is also the standard way to create trait objects (Box<dyn Trait>) for dynamic dispatch. In performance-sensitive code, Box helps move large data without copying it.
Deep Dive
Creating a Box allocates on the heap and returns a pointer:
rustlet b = Box::new(5); println!("b = {b}"); // Deref coercion: acts like &i32
The most common use case is recursive types. Without indirection, the compiler cannot determine the size:
rust// Won't compile — infinite size! // enum List { Cons(i32, List), Nil } // Works — Box has known pointer size enum List { Cons(i32, Box<List>), Nil, } let list = List::Cons(1, Box::new(List::Cons(2, Box::new(List::Nil))));
Box also enables moving large data without copying the underlying bytes:
rustlet huge_array = Box::new([0u8; 1_000_000]); let moved = huge_array; // Moves the pointer, not the data!
For trait objects, Box provides owned dynamic dispatch:
rusttrait Animal { fn speak(&self); } struct Dog; impl Animal for Dog { fn speak(&self) { println!("Woof"); } } let animal: Box<dyn Animal> = Box::new(Dog); animal.speak(); // Dynamic dispatch through vtable
Common Pitfalls
- Using Box when a reference suffices — Box allocates on the heap, which has overhead. If you only need to borrow data temporarily, use a reference instead.
- Forgetting deref coercion — You do not need to manually dereference a Box in most contexts.
&Box<String>automatically coerces to&Stringto&str.
Best Practices
- Use Box for recursive types — It is the idiomatic solution for cons-lists, trees, and other recursive structures.
- Prefer
Box::leakoverunsafefor creating'staticreferences — When you need a'staticreference from owned data,Box::leakis the safe and idiomatic approach.
Summary
- Box<T> is a single-owner heap pointer that frees memory on drop.
- It enables recursive types by providing a fixed-size indirection.
- Deref coercion lets Box behave transparently like a reference.
- Box<dyn Trait> is the standard way to create owned trait objects.
Code Examples
// Binary tree with Box
#[derive(Debug)]
enum Tree<T> {
Leaf(T),
Node {
left: Box<Tree<T>>,
right: Box<Tree<T>>,
},
}
let tree = Tree::Node {
left: Box::new(Tree::Leaf(1)),
right: Box::new(Tree::Node {
left: Box::new(Tree::Leaf(2)),
right: Box::new(Tree::Leaf(3)),
}),
};