🦀 Rust - Smart Pointers
The most common smart pointers are String and Vec<T>.
Smart pointers are data structures that work like pointers under the hood.
Smart pointer implements Deref and Drop traits.
- the
Derefmakes it a reference that can act like the referenced value - the
Dropallows cleaning when it goes out-of-scope - together they are "smart", knows to clean itself but feel like the concrete value
You can also force a drop with
std::mem::drop.
The simplest smart pointer is Box<T>. It allows indirection and store dynamic data in the heap. Those are its only capabilities.
The most common use-cases for smart pointers:
- you want to use a type with unknown size in context that requires a known size
- Rust must know the size of each type at compile-time
- you have huge amounts of data that will change ownership
- to guard against expensive copying on ownership transfer
- you want to own a value but only care about one trait that it implements
- aka. trait object-based generics
Reference Counters are Smart Pointers
Rc<T> implements reference counting for single-threaded code; you are not sure which part of your code finishes with T the last, call Rc::clone to create a new tracked reference and the value is only cleaned after all references are dropped.
You should use
Rc::cloneinstead ofcloneto avoid confusion.
Arc<T> is a multithreaded version of reference counting.
The
Athere stands for "atomic".
Cell<T> allows shared mutability in single-threaded code.
Mutex<T> allows shared mutability in multithreaded code.
RefCell<T> allows manual borrow rules during runtime in single-threaded code.
let counter = Arc::new(Mutex:: new(0));
for _ in 0..10 { let counter = Arc::clone(&counter); }
Trait Object are Smart Pointers
To use variables solely according to trait, you must use trait objects.
You define a trait object type by:
- putting
dyn Traitbehind a reference like&dyn Trait - with a smart pointer like
Box<dyn Trait> - in certain contexts using more modern
impl Trait