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

Managing Shared Mutable State

Safely coordinate updates across concurrent readers using references.

In this lesson, you will learn how to safely coordinate updates to data that needs to be accessed and modified by multiple parts of your program simultaneously.

The Conflict of Shared Mutation

In Rust, the borrow checker enforces a strict rule: you can have many immutable references (&T) or exactly one mutable reference (&mut T), but never both at the same time. When you need to share state that must change, this rule can feel restrictive. To manage this safely, we use the "Interior Mutability" pattern combined with reference counting.

Coordinating Updates

The standard approach to managing shared mutable state is to wrap your data in two specific containers: Rc<T> (or Arc<T> for thread safety) and RefCell<T>.

  • Rc<T>: Provides shared ownership, allowing multiple parts of your code to hold a reference to the same data.
  • RefCell<T>: Moves the borrow checking from compile-time to runtime. It allows you to obtain a mutable reference to the inner data even when the RefCell itself is held immutably.

By combining them, you create a structure where the Rc manages the "shared" aspect, and the RefCell manages the "mutable" aspect.

use std::rc::Rc;
use std::cell::RefCell;

fn main() {
    // We wrap our data in RefCell for mutability, then Rc for sharing
    let shared_data = Rc::new(RefCell::new(10));

    // Create a clone of the Rc pointer
    let owner_two = Rc::clone(&shared_data);

    // Modify the data through one reference
    *shared_data.borrow_mut() += 5;

    // Observe the change from another reference
    println!("Value is now: {}", owner_two.borrow());
}

Why this is safe

This isn't an "escape hatch" that ignores Rust's safety; it simply shifts the enforcement. If you try to borrow the data mutably while another part of your program has already borrowed it (either mutably or immutably), the RefCell will trigger a panic! at runtime. This ensures that you still obey the "one mutable xor many immutable" rule, preventing data races and memory corruption while granting you the flexibility needed for shared state architectures.

Key Takeaway: Use Rc<RefCell<T>> to permit multiple owners to safely mutate shared data by shifting borrow enforcement from compile-time to runtime.