Reading — step 1 of 4
Learn
~1 min readSmart Pointers and Interior Mutability
Rust's borrow rules are checked at COMPILE time. Interior mutability types defer the check to RUNTIME — letting you mutate through a shared reference.
Cell<T> — for Copy types only. Get/set via copy:
use std::cell::Cell;
struct Counter {
count: Cell<i32>, // mutable through &self
}
impl Counter {
fn increment(&self) { // note: &self, not &mut self
self.count.set(self.count.get() + 1);
}
}
The outer borrow can be &self (immutable) but count is still mutable inside.
RefCell<T> — for non-Copy types. Borrow at runtime:
use std::cell::RefCell;
struct Cache {
items: RefCell<Vec<String>>,
}
impl Cache {
fn add(&self, item: String) {
self.items.borrow_mut().push(item); // panics if already borrowed
}
fn get(&self, idx: usize) -> Option<String> {
self.items.borrow().get(idx).cloned()
}
}
borrow() and borrow_mut() are runtime checks. Multiple shared borrows OK; multiple mutable, or shared+mutable, panics.
Common pattern: Rc + RefCell = shared mutable state (single thread):
let shared = Rc::new(RefCell::new(vec![1, 2, 3]));
let copy = Rc::clone(&shared);
copy.borrow_mut().push(4);
println!("{:?}", shared.borrow()); // [1, 2, 3, 4]
For threads, use Arc + Mutex (or RwLock) — same idea, thread-safe.
When to use:
- Most code: don't need interior mutability — borrow checker is sufficient
- When you need to mutate inside an immutable method (cache, counter)
- When you have a graph or doubly-linked structure (Rc/RefCell)
- When you have GUI/observer patterns
Discussion
Ask a question, share an insight, or help someone who’s stuck.
Sign in to post a comment or reply.
Loading…