Smart pointers are data structures that act like a pointer but also have additional metadata and capabilities. In Rust, multiple smart pointers exists including reference counting smart pointer.
Smart pointers are usually implemented using structs that implements the Deref
and Drop
traits. The Deref
trait allows an instance of the smart pointer struct to behave like a reference, and the Drop
trait allows you to customize the code that’s run when an instance of the smart pointer goes out of scope.
In this chapter, 3 types of smart pointers in Rust are covered:
Box<T>
for allocating values on the heapRc<T>
, a reference counting type that enables multiple ownershipRef<T>
and RefMut<T>
, accessed through RefCell<T>
, a type that enforces the borrowing rules at runtime instead of compile time.Box<T>
: Point to Data on HeapBoxes allow you to store data on the heap rather than the stack. They don’t have performance overhead and don’t have many extra capabilities either. It is used when:
You have a type whose size can’t be known at compile time and want to use a value of that type in a context that requires an exact size
// allocating object in the heap
let b = Box::new(5);
println!("b={}",b);
// representing recursive object
enum List {
Cons(i32, Box<List>);
Nil,
}
let list = Cons(1, Box::new(Cons(2, Box::new(Cons(3, Box::new(Nil))))));
You have a large amount of data and you want to transfer ownership but ensure the data won’t be copied
You want to own a value and you care only that it’s a type that implements a particular trait rather than being of a specific type
Deref
TraitImplementing the Deref
trait allows you to customize the behavior of the deference operator *
. Doing so, the smart pointer can be treated like a regular reference, and you can write code that operates on references and use that code with smart pointers too.
use std::ops::Deref;
impl<T> Deref for MyBox<T> {
type Target = T;
fn deref(&self) -> &Self::Target {
&self.0 // fisrt value
}
}
Drop
TraitDrop
trait lets you customize what happens when a value is about to go out of scope. It requires you to implement one method named drop
that takes a mutable reference to self
.
If we want to explicitly call the drop on some variables that has the Drop
trait, we could do std::mem::drop(var)
Rc<T>
, the Reference Counted Smart PointerIn a graph structure, multiple edges might point to the same node, and that node is conceptually owned by all of the edges that point to it. This node shouldn’t be cleaned up unless it doesn’t have any edges pointing to it.
Multiple ownership can be enabled by using Rc<T>
, an abbreviation of reference counting. It keeps track of the number of references to a value to determine whether or not the value is still in use. If there’s no references to a value, the value can be cleaned up.