Course contentsShow
← Rust
Lesson 1046 of 1,9109. Smart Pointers and Interior MutabilityFree lesson

Shadowing vs Mutability

Differentiate between binding shadowing and structural interior mutability.

In this lesson, you will learn how to distinguish between the lexical re-binding of a name through shadowing and the structural modification of data enabled by interior mutability.

Shadowing: The Lexical Illusion

Shadowing is a compiler-level convenience, not a memory-level change. When you shadow a variable, you aren’t modifying the data stored at a specific memory address; you are simply telling the compiler to point the name to a brand-new memory location, effectively hiding the previous instance for the duration of the new scope.

let x = 5;
let x = x + 1; // The first 'x' is shadowed, not modified.

The original x still exists (or is dropped) at its original memory address. This is a local naming scope rule.

Interior Mutability: The Structural Reality

In contrast, interior mutability—using types like RefCell<T> or UnsafeCell<T>—bypasses the borrow checker’s static rules to modify data that is technically held behind an immutable reference. Unlike shadowing, this happens at a stable memory address. If you have a reference to a RefCell, you can change its internal contents without changing the binding of the variable itself.

use std::cell::RefCell;

let data = RefCell::new(10);
// We cannot 're-bind' data, but we can change the memory it points to.
*data.borrow_mut() = 20; 

Why the Distinction Matters

Shadowing is "stateless"—it’s a transformation of values used primarily to convert types or update immutable state cleanly. Interior mutability is "stateful"—it allows for shared, mutable access patterns in complex data structures (like graphs or caches) where the ownership hierarchy doesn't allow for simple &mut references.

While shadowing creates a new binding to represent a new state, interior mutability maintains a single, persistent binding that masks a changing internal state. Confusing the two leads to subtle logic errors: if you shadow a RefCell, you aren't resetting the original cell; you are just giving yourself a new, separate handle to a potentially different memory location.

Key Takeaway: Shadowing creates a new variable binding at a new memory address, whereas interior mutability permits structural change to data at a persistent memory address despite immutable external access.