capypad
0 day streak
rust / intermediate
Snippet

Interior Mutability with Cell and RefCell

Interior mutability allows mutation of data through a shared reference. Cell<T> provides mutation for Copy types, while RefCell<T> provides runtime borrow checking for non-Copy types. In this example, Counter uses Cell for the numeric value and RefCell for the history vector, enabling mutation even with &self references. The borrow checker enforces that only one mutable reference or multiple immutable references exist at runtime.

snippet.rs
rust
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
use std::cell::{Cell, RefCell};
 
struct Counter {
value: Cell<u32>,
history: RefCell<Vec<u32>>,
}
 
impl Counter {
fn new() -> Self {
Counter {
value: Cell::new(0),
history: RefCell::new(Vec::new()),
}
}
 
fn increment(&self) {
let new_val = self.value.get() + 1;
self.value.set(new_val);
self.history.borrow_mut().push(new_val);
}
 
fn get_value(&self) -> u32 {
self.value.get()
}
 
fn get_history(&self) -> Vec<u32> {
self.history.borrow().clone()
}
}
 
fn main() {
let counter = Counter::new();
counter.increment();
counter.increment();
counter.increment();
println!("Value: {}", counter.get_value());
println!("History: {:?}", counter.get_history());
}
Breakdown
1
use std::cell::{Cell, RefCell};
Import Cell for Copy types and RefCell for runtime borrow checking
2
value: Cell<u32>,
Cell wraps Copy type, allowing internal mutation without &mut self
3
history: RefCell<Vec<u32>>,
RefCell wraps non-Copy types with runtime borrow checking
4
self.value.get()
Atomically copies the value from the Cell
5
self.history.borrow_mut().push(new_val);
borrow_mut returns a RefMut guard; panic occurs if already borrowed