Pointers
Raw Pointers
- Need
unsafe block
- Use
*mut T and *const T
Smart Pointers
- Smart Pointers are structs that implement
Deref and Drop traits
- References dont own the data and only store address of the data
- Smart Pointers typically own the data, and store additional information
Deref and DerefMut Traits
std::ops::Deref provides .deref() which deref Smart Pointers using *
Deref is invoked implicitly
- If
T implements Deref<Target = U>:
T implicitly implements all the (immutable) methods of the type U
- Values of type
&T are coerced to values of type &U
- e.g.,
PathBuf implements Deref<Target = Path>, thus implements all the methods of Path
pub trait Deref {
type Target: ?Sized;
fn deref(&self) -> &Self::Target;
}
pub trait DerefMut: Deref {
fn deref_mut(&mut self) -> &mut Self::Target;
}
Drop trait
- A type impl
Drop cannot impl Copy
pub trait Drop {
fn drop(&mut self);
}
// drop method is to take ownership and does nothing with it
fn drop<T>(_x: T) { }
// self.drop() cannot be called explicitly
// use std::mem:drop(instance) isntead
impl Drop for CustomSmartPointer {
fn drop(&mut self) {
println!("Dropping CustomSmartPointer with data `{}`!", self.data);
}
}
Common Smart Pointers
Box<T> and RefCell<T> have single owners;
Box<T> allows immutable or mutable borrows checked at compile time;
Rc<T> enables multiple owners of the same data;
Rc<T> allows only immutable borrows checked at compile time;
RefCell<T> allows immutable or mutable borrows checked at runtime.
Box
// to Point to Data on the Heap
let b = Box::new(5);
// Recursive Types
// cons list
enum List {
Cons(i32, Box<List>),
Nil,
}
let list = List::Cons(1, Box::new(List::Cons(2, Box::new(List::Nil))));
// Err
// dyn: dynamic
Box<dyn std::error::Error>
// use box to wrap differnt types
let range = if first < last {
Box::new(first..last) as Box<dyn Iterator<Iterm = _>>
else {
Box::new((last..first).rev())
}
Rc
- Reference Counted Smart Pointer
- Only for single-threaded scenario; use
Arc for shared threads
Clone will increase ref count but not deep copy
- Automatically defef to
T via Deref trait
- Inherent methods of
Rc are all associated functions
- e.g.,
Rc::new(), Rc::downgrade(&a),Rc::strong_count(&a)
Rc::clone(&r) is the same as r.clone() but full qualified syntax is preferred
- Implemented
AsRef, Borrow, Clone, Debug, Display, Deref and Drop, From
enum List {
Cons(i32, Rc<List>),
Nil,
}
use crate::List::{Cons, Nil};
use std::rc::Rc;
fn main() {
let a = Rc::new(Cons(5, Rc::new(Cons(10, Rc::new(Nil)))));
// Rc::clone() does not do deep copy; but increase ref count
let b = Cons(3, Rc::clone(&a));
let c = Cons(4, Rc::clone(&a));
Rc::strong_count(&a); // 3
}