liveBook · Manning

Box

As explained in Learn Rust in a Month of Lunches

Box is Rust's owning smart pointer that stores a value on the heap while keeping a fixed-size pointer on the stack.

A `Box` is a smart pointer that owns a value stored on the heap. Think of it as a reference that owns what it points to: the compiler knows the size of the `Box` even when the value behind it needs more space. Create one with `Box::new(value)`. section 13.2 section 13.2.1

Put a value in a Box

`let my_box = Box::new(1);` puts the integer in a `Box`. Use `*my_box` to get to the value, much as you would with a reference. section 13.2.1

Why bother? Consider a struct that may contain another instance of itself. A field of type `Option<Holder>` makes the compiler report that `Holder` has infinite size: each `Holder` might contain another. Changing the field to `Option<Box<Holder>>` gives it a size the compiler can know. section 13.2.1

#[derive(Debug)]
struct Holder {
    next_holder: Option<Box<Holder>>
}
 
fn main() {
    let x = Holder {
        next_holder: Some(Box::new(Holder {
            next_holder: Some(Box::new(Holder { next_holder: None })),
        })),
    };
 
    println!("{x:#?}");
}

The `next_holder` field uses `Option<Box<Holder>>`. `Some(Box::new(...))` adds another holder; `None` ends the chain. section 13.2.1

A `Box` also helps when a value is known by its trait rather than its concrete type. Different types implementing one trait can have different sizes, so a function cannot return the trait as an unboxed value. `Box<dyn Trait>` provides a return type of known size. The `dyn` indicates dynamic dispatch: Rust determines the concrete type at run time rather than making a generic type concrete before run time. section 13.2.2

trait JustATrait {}
 
enum EnumOfNumbers {
    I8(i8),
    AnotherI8(i8),
    OneMoreI8(i8),
}
impl JustATrait for EnumOfNumbers {}
 
 
fn returns_just_a_trait() -> Box<dyn JustATrait> {
    let some_enum = EnumOfNumbers::I8(8);
    Box::new(some_enum)
}

The function returns `Box<dyn JustATrait>` and places a concrete enum value inside with `Box::new`. section 13.2.2

A common use is `Box<dyn Error>` when a function can return different error types. The concrete error is still inside, but ordinary access is through the `Error` trait. If you need to check for a particular concrete error, you can try `downcast_ref()`; it tests one type at a time. Boxing makes these cases possible, though recursive structures can still be awkward to work with under Rust’s ownership and borrowing rules. section 13.2.3 section 13.2.4 section 13.2.1

How Learn Rust in a Month of Lunches covers it

How deep it goes
Works through construction, dereferencing, recursive-type compiler feedback, trait objects, multiple errors, and downcasting; does not develop linked-list construction.
Examples
Shows a boxed integer, a recursive struct corrected after a compiler error, a boxed trait return, and functions returning multiple error types.
What it assumes
Builds on references, ownership, generics, and traits while introducing Box construction and explaining dynamic dispatch in plain terms.
What you can do after
Apply it via Rust’s `Box::new` to construct recursive values or return `Box<dyn Error>`, then try downcasting when the concrete error matters.
How it connects
Connects ownership and references to recursive types, traits, dynamic dispatch, type erasure, and error handling.

Also explained in

Compare how 4 books explain Box →

Related concepts

This explainer was generated by Manning's knowledge graph from the text of Learn Rust in a Month of Lunches. The section links point to the parts of the book it draws on.