The most straightforward of the standard smart pointers is the Box. A Box does what we've been discussing so far: it stores a data value on the heap, while ensuring that it still follows the lifetime rules as if it were actually part of the Box value itself.
Here's an example. First, we'll create a data type for the data we want to store on the heap:
pub struct Person {
pub name: String,
pub validated: bool,
}
Now, creating and using the Box itself is easy:
let jack = Box::new(Person { name: "Jack".to_string(), validated: true });
let x = &jack.name;
println!("The person in the box is {}", x);
The first line creates a Box. We have to give it a data value to store, because one thing Rust is not okay with is an empty Box, so we initialize a Person object and pass it to the function, which creates a new Box to be used as its internal value.
Once we have an initialized the Box, we can mostly treat it as if it was a normal borrow of the contained data. We can move the data back out onto the stack by dereferencing it:
let x = *jack;
This moves the Person value from inside the Box named jack to the x variable, and renders jack unusable.
We can also access the contained data value's data and functions through the Box, again as if it were a borrow of the contained data:
let x = &jack.name;
println!("The person in the box is {}", x);
Here, we're asking to borrow jack.name into x, then printing out that name. We could have also gotten the same result by doing the following:
println!("The person in the box is {}", jack.name);
But that actually works in a very different way. The first example borrows the name, and then prints out that borrowed String value. The second one actually calls a function called jack.name.fmt, which has an immutable borrow as its self parameter. This works out because Rust is smart about dereferencing and function calls.