Reading — step 1 of 6
Learn
Most Rust values live on the stack. Sometimes you need heap allocation, shared ownership, or self-referential structures. Smart pointers are types that wrap a value and provide additional capabilities.
Box<T> — heap allocation
let boxed: Box<i32> = Box::new(42);
println!("{}", *boxed); // 42 — dereference to access
Box<T> allocates on the heap and owns the value. Use it for:
- Recursive types that the compiler can't size (linked lists, trees)
- Trait objects:
Box<dyn Display> - Transferring ownership of large values without copying
Classic recursive type:
enum List {
Cons(i32, Box<List>), // Box breaks the infinite size
Nil,
}
Rc<T> — single-threaded shared ownership
When multiple parts of your code need to OWN the same value (like a shared graph node), Rc<T> does reference counting:
use std::rc::Rc;
let a = Rc::new(String::from("hello"));
let b = Rc::clone(&a);
let c = Rc::clone(&a);
println!("{} refs", Rc::strong_count(&a)); // 3
// when all three drop, the String is freed
Rc::clone doesn't copy the value — it bumps the reference count. Each Rc<T> deref'd gives you a &T.
Rc is single-threaded only — sharing across threads requires Arc.
Arc<T> — atomic, thread-safe shared ownership
use std::sync::Arc;
use std::thread;
let data = Arc::new(vec![1, 2, 3]);
let mut handles = vec![];
for _ in 0..3 {
let d = Arc::clone(&data);
handles.push(thread::spawn(move || {
println!("thread sees: {:?}", d);
}));
}
for h in handles { h.join().unwrap(); }
Atomic ref count → safe to share across threads. Slightly slower than Rc due to atomic operations.
RefCell<T> — interior mutability (single-threaded)
Rust's borrow rules apply at COMPILE time. RefCell<T> moves them to RUNTIME — useful when the compiler can't prove your code is safe but you know it is:
use std::cell::RefCell;
let cell = RefCell::new(5);
*cell.borrow_mut() += 10;
println!("{}", cell.borrow()); // 15
Breaks the borrow rules at compile time but enforces them at runtime — borrow_mut() while another borrow() is active panics.
Common combinations
Rc<RefCell<T>>— shared mutable state in single-threaded code (e.g., graph nodes that need updating).Arc<Mutex<T>>— shared mutable state across threads. Mutex is the threaded equivalent of RefCell.
Common mistakes
- Using
Rcacross threads — compile error. UseArc. - Creating reference cycles with
Rc— leaks memory. UseWeakfor one direction. - Reaching for smart pointers when borrowing would do — adds complexity for no benefit.
- Mutating through
RefCellfrom two places — runtime panic. Stick to one mutable borrow at a time.
Discussion
Ask a question, share an insight, or help someone who’s stuck.
Sign in to post a comment or reply.
Loading…