Interior mutability is a family of patterns that allows mutation through a shared reference, with the borrowing rules enforced at runtime rather than at compile time. This is needed when the borrow checker cannot statically prove that a mutation is safe, but you can still guarantee it through other means such as single-threaded access or explicit locking. Two of the most common interior-mutability types are Cell<T> and RefCell<T>.
Cell<T> is restricted to Copy types and works by swapping the value in place: you call cell.set(x) to replace the contents, and cell.get() to copy them out. There is no runtime tracking of borrows, and so no possibility of a runtime panic from this style. RefCell<T>, by contrast, works for any T and enforces the aliasing-XOR-mutability rule dynamically. RefCell::borrow() returns a Ref guard that acts as a shared reference and releases the borrow when dropped, while RefCell::borrow_mut() returns a RefMut guard that acts as a mutable reference. Violating the rules — for example, calling borrow_mut() while a Ref is alive — triggers a panic! rather than a compile-time error, shifting the failure mode from build time to runtime.
For multi-threaded code, the interior-mutability story is anchored by Mutex<T> and RwLock<T>. A Mutex<T> provides exclusive access: locking returns a MutexGuard smart pointer that dereferences to T and releases the lock when dropped. An RwLock<T> is a reader-writer lock that allows either many concurrent shared readers or exactly one exclusive writer, with the choice enforced at runtime. These primitives are essential when the type system alone cannot prove the absence of data races, but the combination of Send/Sync bounds on what they guard keeps safe Rust data-race-free in practice.