Smart Pointers are data structures that behave like Pointers but have additional metadata and additional functionality. Unlike smart Pointers, references are Pointers that only borrow data. Most smart Pointers own the data they point to, that is, they own the data.
Box
The boxing type (box) allows us to store data on the heap and keep a pointer to the heap data in the stack.
Usage scenarios
- When you have a type whose size cannot be determined at compile time, but you want to use the value of that type in a context that requires a fixed size.
- When ownership of a large amount of data needs to be passed, but replication of a large amount of data is not desirable.
- When you want a type value that implements the specified trait, but you don’t care about the specific type.
Use the packing
let b = Box::new(5);
println!("{}", b); / / 5
Copy the code
Also, like any other value that has ownership, boxing is released when it leaves its scope, including Pointers and data on the heap.
Use boxing to define recursive types
Recursion is impossible with primitive types in Rust, but you can also try to implement a linked list data structure yourself and get an error from Rust because Rust cannot determine the size of a recursive type and thus cannot compile.
Use enumeration to implement the linked list structure
Let’s use Rust to try to implement a linked list.
#[derive(Debug)]
enum List {
Cons(i32, List), // error, recursive types have an infinite size
Nil,
}
let list = List::Cons(1,
List::Cons(2,
List::Cons(3, List::Nil)
)
);
println!("{:? }", list);
Copy the code
Because Rust needs to know the size of all types at compile time, and recursion is infinite at run time, it is impossible to calculate the size of recursion at compile time
Use Box to fix the size of the recursive type
Let’s try again using the Box type to see how to implement a linked list:
#[derive(Debug)]
enum List {
Node(i32.Box<List>), // Use the Box tag type
Nil,
}
let list = List::Node(1.Box::new(List::Node(2.Box::new(List::Node(3.Box::new(List::Nil))
)
))
);
println!("{:? }", list);
// Node(1, Node(2, Node(3, Nil)))
Copy the code
Because Box is a pointer, Rust can determine the exact size of a Box at compile time. The size of a pointer is always constant; it does not change depending on the size of the data it points to.
The structure implements the linked list structure
We used enumerations above to implement lists. We can also use structs to implement lists:
#[derive(Debug)]
struct Node<T> {
value: T,
next: Box<Option<Node<T>>>
}
let list = Node {
value: 1,
next: Box::new(Some(Node {
value: 1,
next: Box::new(None)}}));println!("{:? }", list);
// Node { value: 1, next: Some(Node { value: 1, next: None }) }
Copy the code
The Box type is relatively simple, so we won’t cover much in this section. We’ll cover smart pointer related traits and more smart pointer types later.