Skip to content

Chapter 6 of 8

Interior Mutability and Runtime Enforcement

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.

All chapters
  1. 1Ownership Rules and Memory
  2. 2Moves, Copy, and Clone
  3. 3Borrowing and the Borrow Checker
  4. 4Lifetimes, Variance, and PhantomData
  5. 5Slices, Strings, and Deref Coercion
  6. 6Interior Mutability and Runtime Enforcement
  7. 7Shared Ownership Across Threads
  8. 8Patterns, Iteration, and Unsized Types

Drill it

Reading is not remembering. These come from the Rust Ownership And Borrowing Explained deck:

Q

What are the three ownership rules in Rust?

Each value in Rust has an owner. There can only be one owner at a time. When the owner goes out of scope, the value is dropped.

Q

What happens to a value when its owner goes out of scope in Rust?

It is dropped — its drop function runs and its memory is freed.

Q

Which standard library function is called when a value goes out of scope?

drop, from the Drop trait, is called automatically at the end of the variable's scope.

Q

What is a "move" in Rust?

A transfer of ownership: assigning a value to another variable or passing it to a function moves the value, invalidating the source binding.