Interior Mutability: RefCell, Cell
Learn about `RefCell` and `Cell` for interior mutability, allowing mutable access to data through an immutable reference, safely.
Interior Mutability: RefCell, Cell is a free Learn Rust Coding lesson on CoddyKit — lesson 2 of 3. You can read the complete lesson below for free — then practise it hands-on in the browser with a built-in code editor and a 24/7 AI tutor. It is part of the Learn Rust Coding learning path, one of 3 lessons in the course, and your progress syncs across the web and the CoddyKit app.
What is Interior Mutability?
In Rust, the borrowing rules usually prevent you from having a mutable reference to data if you already have an immutable reference to it. This ensures data safety.
Interior mutability is a design pattern that allows you to mutate data even when you only have an immutable reference to it. It's like a controlled exception to Rust's usual rules, used in specific situations.
`Cell<T>`: For Copy Types
The Cell<T> type provides interior mutability for types that implement the Copy trait (like integers, booleans, characters). It works by replacing the value inside.
get(): Returns a copy of the value inside theCell.set(value): Replaces the value inside theCellwith a new one.
It's simple and efficient for small, copyable data.
Using `Cell` to Update Values
Here's a basic example of Cell. Notice how we can change the value inside the Cell even though the Cell itself is declared as immutable.
use std::cell::Cell;
fn main() {
let my_num = Cell::new(10);
println!("Initial value: {}", my_num.get());
my_num.set(20);
println!("Updated value: {}", my_num.get());
let x = &my_num;
x.set(30); // Still works via immutable reference!
println!("Via immutable ref: {}", my_num.get());
}`RefCell<T>`: For Non-Copy Types
When you need interior mutability for types that do not implement Copy (like String, Vec, or custom structs), you use RefCell<T>.
RefCell allows you to get mutable references to the inner data, but it enforces Rust's borrowing rules at runtime, not compile time.
`RefCell`'s Runtime Borrowing
RefCell provides methods that return smart pointers:
borrow(): Returns aRef(an immutable smart pointer). You can have multiple immutable borrows at once.borrow_mut(): Returns aRefMut(a mutable smart pointer). You can have only one mutable borrow at a time.
If you violate these rules at runtime, your program will panic!.
Using `RefCell` (Immutable Borrow)
Here, we use borrow() to get an immutable reference to the String inside the RefCell. We can print its content.
use std::cell::RefCell;
fn main() {
let my_string_cell = RefCell::new(String::from("Hello"));
let s1 = my_string_cell.borrow();
println!("Value: {}", *s1); // Dereference Ref to get String
let s2 = my_string_cell.borrow(); // Multiple immutable borrows are fine
println!("Another value: {}", *s2);
}Using `RefCell` (Mutable Borrow)
Now, let's get a mutable reference using borrow_mut(). This allows us to modify the String. Note that once s_mut is in scope, no other borrows (mutable or immutable) are allowed.
use std::cell::RefCell;
fn main() {
let my_string_cell = RefCell::new(String::from("World"));
{ // Scope for the mutable borrow
let mut s_mut = my_string_cell.borrow_mut();
s_mut.push_str(", Rust!");
}
// s_mut is out of scope here, so we can borrow again
let s_final = my_string_cell.borrow();
println!("Final value: {}", *s_final);
}The `RefCell` Runtime Panic
If you try to get a mutable borrow while another mutable borrow (or any immutable borrow) is active, RefCell will cause your program to panic! at runtime. This prevents data corruption.
Run this code to see it in action! It will crash with a "borrow already in use" error.
use std::cell::RefCell;
fn main() {
let my_value = RefCell::new(vec![1, 2, 3]);
let _first_mut_borrow = my_value.borrow_mut();
println!("First mutable borrow is active.");
// This line will cause a runtime panic!
// Try commenting it out to see the program run successfully.
let _second_mut_borrow = my_value.borrow_mut();
println!("This line will not be reached.");
}`Cell` vs. `RefCell` Summary
Choosing between Cell and RefCell depends on your data type and how you need to interact with it:
Cell<T>: Use for types that implementCopy. It replaces the entire value and is generally simpler and more performant.RefCell<T>: Use for types that do not implementCopy. It provides references to the inner data and enforces borrowing rules at runtime, allowing more complex mutations.
Quick Check: Cell or RefCell?
You have a struct that needs to store a mutable counter (u32) and a mutable list of names (Vec<String>), and both need to be updated through an immutable reference to the struct. Which interior mutability types would you use for each field?
Recap: Interior Mutability
You've learned about Rust's interior mutability pattern, which allows modifying data through an immutable reference in a controlled, safe way.
Cell<T>: ForCopytypes, replaces the inner value.RefCell<T>: For non-Copytypes, provides runtime-checked mutable/immutable references.- Violating
RefCell's rules leads to a runtime panic, ensuring safety.
These types are crucial for patterns like mock objects, circular references, or when a shared immutable reference needs to track internal state.
Frequently asked questions
Is the “Interior Mutability: RefCell, Cell” lesson free?
Yes — the full text of “Interior Mutability: RefCell, Cell” is free to read here on the web, and the Learn Rust Coding course includes 3 lessons in total. To practise it interactively (a built-in code editor and a 24/7 AI tutor) and unlock the rest of the Learn Rust Coding course, upgrade to CoddyKit PRO.
What will I learn in “Interior Mutability: RefCell, Cell”?
Learn about `RefCell` and `Cell` for interior mutability, allowing mutable access to data through an immutable reference, safely. You practise Learn Rust Coding with hands-on code you run directly in the browser, and a 24/7 AI tutor answers your questions as you work through the lesson.
Do I need any experience to start Learn Rust Coding?
No prior experience is required. Learn Rust Coding on CoddyKit is structured for beginners through advanced learners; this is — lesson 2 of 3, so you can start here or from the beginning and move at your own pace.
How long does the “Interior Mutability: RefCell, Cell” lesson take?
Most CoddyKit lessons take about 5–10 minutes. Each one is bite-sized and interactive, so you make steady progress and pick up exactly where you left off across the web and the app.
Can I write and run code in this Learn Rust Coding lesson?
Yes. Every Learn Rust Coding lesson includes a built-in code editor, so you write and run real code right in your browser and get instant AI feedback — no local setup required.
All lessons in this course
- Box, Rc, and Arc Smart Pointers
- Interior Mutability: RefCell, Cell
- Fearless Concurrency with Threads