Course contentsShow
← Rust
Lesson 292 of 1,9103. Borrowing and ReferencesFree lesson

The Interior Mutability Pattern

Swap immutable logic for internal mutability when data modification is necessary.

In this lesson, you will learn how to bypass Rust's strict "immutable-by-default" borrowing rules to modify data even when you only hold a shared reference to it.

The Problem: Immutable Restrictions

Usually, if you have a shared reference (&T), Rust prevents you from changing the data. This is a core part of the "aliasing XOR mutability" rule: if multiple parts of your code are looking at the same data, none of them should be allowed to change it unexpectedly.

However, sometimes you have a structure that you want to share across different parts of your program (holding only &T), but you still need to perform internal "housekeeping" tasks, such as updating a cache, logging, or modifying a specific field.

The Solution: Interior Mutability

The Interior Mutability pattern allows you to mutate data even when it is held behind a shared reference. It works by shifting the responsibility of enforcing borrowing rules from compile-time to runtime.

Think of it like a "locked box": you can share the box itself with everyone, but to actually change what’s inside, you must interact with the box's lock.

A Concrete Example

Consider a scenario where you want to count how many times a configuration object has been accessed. Because the object is shared, you can't use a normal &mut self method. Instead, you wrap the counter in an interior mutability type:

use std::cell::Cell;

struct Config {
    // We use Cell for interior mutability of a simple value
    access_count: Cell<u32>,
}

fn log_access(config: &Config) {
    let new_count = config.access_count.get() + 1;
    config.access_count.set(new_count);
}

Here, log_access only requires a &Config (a shared reference). Even though the reference is immutable, the Cell allows us to reach inside and update the access_count field.

The compiler trusts that you are managing access correctly. If you try to perform conflicting operations (like attempting to mutate the data while it is currently being borrowed elsewhere), the program will trigger a runtime panic rather than letting your memory become inconsistent.

Key Takeaway: The Interior Mutability pattern enables you to modify data through a shared reference by offloading borrow checking from the compiler to runtime safety mechanisms.