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
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