The Box Type
Box puts a value on the heap and gives you a simple handle to it, which is handy for big or self-referencing data.let name = Box::new(value);
let value = *name;
enum List {
Cons(i32, Box<List>),
Nil,
}
Boxing a Value
Box::new(value) moves a value onto the heap and returns a Box<T> pointing to it. The Box itself lives on the stack and owns the heap data.
Example: Boxing a Value
// Entry point: execution of the program starts here
fn main() {
// Declare an immutable variable `boxed_number`, set to `Box::new(42)`
let boxed_number = Box::new(42);
// Print "Boxed value: {}" to the console, substituting in `boxed_number` (with a trailing newline)
println!("Boxed value: {}", boxed_number);
}
Login to try C/C++/Java/PHP code in the editor
Boxing a Recursive Type
Recursive types, like a simple linked list, would have an infinite size without indirection. Wrapping the recursive field in Box gives it a fixed, known size, since a Box is just a pointer.
Example: Boxing a Recursive Type
// Define an enum `List` listing its possible variants
enum List {
Cons(i32, Box<List>),
Nil,
}
// Bring `List::{Cons, Nil}` into scope
use List::{Cons, Nil};
// Entry point: execution of the program starts here
fn main() {
// Declare an immutable variable `list`, set to `Cons(1, Box::new(Cons(2, Box::new(Nil))))`
let list = Cons(1, Box::new(Cons(2, Box::new(Nil))));
// If `list` matches `Cons(value, _)`, bind and run this block
if let Cons(value, _) = list {
// Print "First value: {}" to the console, substituting in `value` (with a trailing newline)
println!("First value: {}", value);
}
}
Login to try C/C++/Java/PHP code in the editor
Dereferencing a Box
The * operator dereferences a Box, giving direct access to the value it contains, just like dereferencing any other pointer-like type.
Example: Dereferencing a Box
// Entry point: execution of the program starts here
fn main() {
// Declare an immutable variable `boxed`, set to `Box::new(10)`
let boxed = Box::new(10);
// Declare an immutable variable `doubled`, set to `*boxed * 2`
let doubled = *boxed * 2;
// Print "Doubled: {}" to the console, substituting in `doubled` (with a trailing newline)
println!("Doubled: {}", doubled);
}
Login to try C/C++/Java/PHP code in the editor
Box for Trait Objects
Box<dyn Trait> is a common way to store a value whose exact concrete type is not known at compile time, as long as it implements a specific trait.
Example: Box for Trait Objects
// Define a trait `Speak` describing shared behavior
trait Speak {
// Define the function `say` taking `&self` and returning a `String;`
fn say(&self) -> String;
}
// Define a struct `Dog` to group related fields together
struct Dog;
// Implement the `Speak` trait for `Dog`
impl Speak for Dog {
// Define the function `say` taking `&self` and returning a String
fn say(&self) -> String {
String::from("Woof!")
}
}
// Entry point: execution of the program starts here
fn main() {
// Declare an immutable variable `animal` (a `Box<dyn Speak>`), set to `Box::new(Dog)`
let animal: Box<dyn Speak> = Box::new(Dog);
// Print "{}" to the console, substituting in `animal.say()` (with a trailing newline)
println!("{}", animal.say());
}
Login to try C/C++/Java/PHP code in the editor
- Using
Box<T>when a value would fit perfectly fine on the stack, adding unnecessary heap allocation overhead. - Forgetting a recursive data type (like a linked list node) needs
Box(or similar) to have a known, finite size. - Assuming
Boxallows shared ownership -- it is single-owner, just like any other owned value; useRcfor sharing.
Box<T>allocates a value on the heap and owns it, giving you a fixed-size pointer to store on the stack.Boxis essential for recursive types, since without it the compiler couldn't compute a finite size for the type.- Dereferencing a
Boxwith*gives direct access to the inner value. Boxhas single ownership semantics, just like other owned values -- it is dropped and freed automatically.
Chapter Quiz — Complete all 7 topics to unlock
0/7 topics done
Complete these topics first: