RefCell<T> / Cell<T>
RefCell<T> and Cell<T> are smart pointers that provide interior mutability. They enforce Rust's borrowing rules at runtime rather than compile time, allowing you to mutate values through immutable references.
Syntax
use std::cell::{Cell, RefCell};
// RefCell: use for non-Copy types (String, Vec, etc.)
let r = RefCell::new(value);
let borrowed = r.borrow(); // Immutable borrow (&T)
let mut borrowed = r.borrow_mut(); // Mutable borrow (&mut T)
// Cell: use for Copy types (i32, bool, etc.)
let c = Cell::new(value);
c.set(new_value);
c.get();
Method List
| Method | Description |
|---|---|
| RefCell::new(v) | Wraps the value v in a RefCell. |
| borrow() | Returns an immutable borrow (Ref<T>). Panics if a mutable borrow is already active. |
| borrow_mut() | Returns a mutable borrow (RefMut<T>). Panics if any other borrow is already active. |
| try_borrow() | Returns Result<Ref<T>, BorrowError> without panicking on failure. |
| try_borrow_mut() | Returns a mutable borrow as a Result type. Does not panic on failure. |
| Cell::new(v) | Wraps a Copy value in a Cell. |
| cell.get() | Returns a copy of the value (requires the Copy trait). |
| cell.set(v) | Replaces the value. No borrow is needed to modify it. |
Sample Code
use std::cell::{Cell, RefCell};
// A struct whose internal state can be mutated through an immutable reference
struct Counter {
count: Cell<u32>,
log: RefCell<Vec<String>>,
}
impl Counter {
fn new() -> Self {
Counter {
count: Cell::new(0),
log: RefCell::new(vec![]),
}
}
// Internal state can be mutated even with &self (immutable reference).
fn increment(&self, label: &str) {
let n = self.count.get() + 1;
self.count.set(n);
self.log.borrow_mut().push(format!("{}: {}", label, n));
}
fn show(&self) {
for entry in self.log.borrow().iter() {
println!("{}", entry);
}
}
}
fn main() {
let c = Counter::new();
c.increment("a"); // a: 1
c.increment("b"); // b: 2
c.increment("c"); // c: 3
c.show();
println!("total: {}", c.count.get()); // total: 3
}
Overview
Rust's compile-time borrow checker is powerful, but there are cases where you need to mutate internal state through an immutable reference by design. RefCell<T> and Cell<T> provide this "interior mutability." Borrowing rules are checked at runtime rather than at compile time.
Cell is suited for lightweight Copy types, while RefCell is used for non-Copy types such as String or Vec. Both are single-threaded only.
Violating RefCell's borrowing rules — such as holding a mutable and an immutable borrow at the same time — results in a runtime panic, not a compile error. If the borrow boundaries are unclear, use the safer try_borrow() family of methods.
If you find any errors or copyright issues, please contact us.