Box<T>
Box is an owned pointer to data on the heap:
fn main() { let five = Box::new(5); println!("five: {}", *five); }
Box<T> implements Deref<Target = T>, which means that you can call methods from T directly on a Box<T>.
Recursive data types or data types with dynamic sizes need to use a Box:
#[derive(Debug)] enum List<T> { /// A non-empty list: first element and the rest of the list. Element(T, Box<List<T>>), /// An empty list. Nil, } fn main() { let list: List<i32> = List::Element(1, Box::new(List::Element(2, Box::new(List::Nil)))); println!("{list:?}"); }
-
Boxis likestd::unique_ptrin C++, except that it’s guaranteed to be not null. -
A
Boxcan be useful when you:- have a type whose size that can’t be known at compile time, but the Rust compiler wants to know an exact size.
- want to transfer ownership of a large amount of data. To avoid copying large amounts of data on the stack, instead store the data on the heap in a
Boxso only the pointer is moved.
-
If
Boxwas not used and we attempted to embed aListdirectly into theList, the compiler would not be able to compute a fixed size for the struct in memory (theListwould be of infinite size). -
Boxsolves this problem as it has the same size as a regular pointer and just points at the next element of theListin the heap. -
Remove the
Boxin the List definition and show the compiler error. We get the message “recursive without indirection”, because for data recursion, we have to use indirection, a Box or reference of some kind, instead of storing the value directly.
More to Explore
Niche অপটিমাইজেশন
#[derive(Debug)] enum List<T> { Element(T, Box<List<T>>), Nil, } fn main() { let list: List<i32> = List::Element(1, Box::new(List::Element(2, Box::new(List::Nil)))); println!("{list:?}"); }
A Box cannot be empty, so the pointer is always valid and non-null. This allows the compiler to optimize the memory layout: