Interior Mutability in Rust
Interior mutability lets you mutate a value via a shared/read reference.
Normally, the type system guarantees there cannot be an active read reference while a write reference exists to the same value. Interior mutability enables mutating values behind a shared reference by either copying/replacing values (single-threaded cell types) or tracking borrows at runtime (borrow-checked cells or thread-safe locks).
Cell
std::cell::Cell<T> lets you mutate a value via a shared/read reference to avoid undefined behaviour; it only lets you copy T if T implements Copy or replace T.
It can also be used only in a single thread.
fn f(a: &i32, b: &mut i32) {
let before = *a;
*b += 1;
let after = *a;
if before != after {
x(); // never happens
}
}
x is never called because Rust guarantees that both a and b can't reference the same number, as there can't be a read reference &a while we have a write reference &mut b to the same value.
But with Cell:
use std::cell::Cell;
fn f(a: &Cell<i32>, b: &Cell<i32>) {
let before = a.get();
b.set(b.get() + 1);
let after = a.get();
if before != after {
x();
}
}
x might be called now, as both a and b can point to the same value.
Use cell.take() when T doesn't implement Copy.
use std::cell::Cell;
fn f(vec: &Cell<Vec<i32>>) {
let mut v = vec.take();
v.push(4);
vec.set(v);
}
take replaces the internal vector with an empty vector.
RefCell
std::cell::RefCell lets you take a mutable reference to the value without cloning it, at a small runtime cost. It maintains a count along with the value, and taking a mutable reference while there are shared references, or vice versa, causes a panic.
use std::cell::RefCell;
fn f(vec: &RefCell<Vec<i32>>) {
vec.borrow_mut().push(1);
}
But both Cell and RefCell can't be sent across threads.
