A smart pointer in Rust - Box<T>
Rust also has a smart pointer type with unique ownership called Box<T>
. Putting a value on the heap can be done through Box<T>
in a number of ways:
fn main() { let b1: Box<i32> = Box::new(42); let on_stack: i32 = 43; let b2: Box<i32> = on_stack.into(); let back_on_stack: i32 = *b2; let boxed_array: Box<[i32]> = Box::new([1, 2, 3]); let deep_copied: Box<i32> = b1.clone(); }
What is interesting is that Box<T>
allows copying, whereas std::unique_ptr<T>
did not allow copying. Rust actually does something smart here: Remember that Rust provides the Clone
trait for values that have non-trivial copy operations? Well in Rust we can implement a trait on a type conditionally, like so:
#![allow(unused)] fn main() { impl<T: Clone, A: Allocator + Clone> Clone for Box<T, A> { fn clone(&self) -> Self { //... clone implementation } } }
Ignoring the A
generic type for now, this statement implements the Clone
trait for Box<T>
only if T
implements the Clone
trait! This is a common pattern in Rust to propagate specific behaviour from a wrapped type (e.g. T
) to its wrapper (e.g. Box<T>
). Box<T>
has a lot of these conditional trait implementations to make Box<T>
behave like T
in most situations. For example, we can test two instances of Box<T>
for equality if T
can be tested for equality (which is realized through the Eq
trait):
pub fn main() { let b1: Box<i32> = Box::new(42); let b2: Box<i32> = Box::new(42); println!("{}", b1 == b2); }
b1
and b2
are located at different memory addresses, but their values are equal, so b1 == b2
resolves to true
.
There is not much more to say about Box<T>
at this point, besides that it is the main way of getting stuff on the heap in Rust. Let's move on to something more interesting then!