Box<T>
Box<T> owns heap-allocated T with single ownership - like Vec but single element.
Recipe
enum List { Cons(i32, Box<List>), Nil }
use List::{Cons, Nil};
fn main() {
let list = Cons(1, Box::new(Cons(2, Box::new(Nil))));
}When to reach for this: Recursive types, large values on stack avoidance, trait objects Box<dyn Trait>.
Working Example
trait Draw { fn draw(&self); }
struct Circle;
impl Draw for Circle { fn draw(&self) { println!("circle"); } }
fn main() {
let shapes: Vec<Box<dyn Draw>> = vec![Box::new(Circle)];
for s in shapes { s.draw(); }
}What this demonstrates:
- Recursive enum with
Boxfor indirection - Trait object on heap via
Box<dyn Draw> - Single owner per box
Deep Dive
Box implements Deref, Drop frees heap. Box<[T]> from Vec via into_boxed_slice. No refcount overhead.
Gotchas
- Box everywhere unnecessarily - Prefer owned struct on stack if small. Fix: Profile stack size.
- Box
common - Ok for apps; libraries prefer typed errors. - Moving out of box -
*boxorBox::into_inner(1.66+). - Pin<Box<T>> - For self-referential async - advanced.
- Box in no_std -
alloc::boxed::Boxwith allocator.
Alternatives
| Alternative | Use When | Don't Use When |
|---|---|---|
Vec | Dynamic array | Single value indirection |
Arc | Shared ownership | Single owner |
&T | Borrow | Need ownership transfer |
FAQs
Box vs Vec?
Box single element; Vec buffer.into_inner?
Extract T consuming box.box syntax?
`box 5` nightly only historically - use Box::new.Pin box?
Async/state machine pinning.FFI Box?
Rare - raw alloc instead.zero sized?
Box<ZST> still allocates unless optimized.serde?
Box<T> transparent like T.clone box?
If T: Clone.default?
Box::default if T: Default.try_new?
Fallible allocation unstable/experimental paths.Related
Stack versions: This page was written for Rust 1.97.0 (edition 2024), Tokio 1.x, Axum 0.8, serde 1.0, sqlx 0.8, clap 4, and Polars 0.46+.