Rc gives shared ownership but only immutable access. RefCell<T> supplies the missing half: the ability to mutate through a shared reference, by moving the borrow check from compile time to runtime. This is interior mutability.
Borrow rules, checked at runtime
Normally the borrow checker enforces aliasing XOR mutation at compile time. RefCell lets you opt into runtime checking instead: .borrow() gives a shared reference, .borrow_mut() a mutable one, and it tracks them at runtime. Break the rule — two mutable borrows at once — and it panics instead of failing to compile. Same guarantee, enforced later.
Why move the check to runtime?
Some valid patterns can't be proven safe at compile time — a value mutated through a shared structure, a mock object accumulating calls in a test, a graph node updated from elsewhere. RefCell says 'trust me, I'll uphold the borrow rules; check me at runtime.' You trade a compile-time guarantee for flexibility, accepting a possible panic if you break the rule.
Rc + RefCell: shared and mutable
The classic combo is Rc<RefCell<T>>: Rc for multiple owners, RefCell for mutating the shared value. It's how you build a tree whose nodes can be updated, or shared mutable state in single-threaded code. (In multithreaded code the equivalent is Arc<Mutex<T>> — note the exact parallel.)