0
0
Rustprogramming~15 mins

Mutable variables in Rust - Deep Dive

Choose your learning style9 modes available
Overview - Mutable variables
What is it?
Mutable variables in Rust are variables that you can change after you create them. By default, variables in Rust cannot be changed once set. To make a variable mutable, you add the keyword 'mut' before its name. This lets you update the value stored in that variable later in your program.
Why it matters
Mutable variables exist because programs often need to change data as they run, like updating a score in a game or changing a setting. Without mutable variables, you would have to create new variables every time you want to change something, which is inefficient and confusing. Rust’s approach helps keep programs safe by making you explicitly say when a variable can change, reducing bugs.
Where it fits
Before learning mutable variables, you should understand how to declare and use basic variables in Rust. After this, you can learn about ownership and borrowing, which explain how Rust manages memory safely when variables change.
Mental Model
Core Idea
A mutable variable is like a labeled jar that you can open and replace the contents of, while an immutable variable is a sealed jar you cannot change once closed.
Think of it like...
Imagine you have a notebook where you write your daily to-do list. If the notebook is mutable, you can erase and rewrite tasks as your plans change. If it is immutable, once you write a task, you cannot erase or change it, only add a new notebook.
┌───────────────┐       ┌───────────────┐
│ Immutable Var │       │ Mutable Var   │
│ (sealed jar)  │       │ (open jar)    │
│ Value: 10     │       │ Value: 10     │
│ Can't change  │       │ Can change    │
└───────────────┘       └───────────────┘
Build-Up - 6 Steps
1
FoundationDeclaring immutable variables
🤔
Concept: Variables in Rust are immutable by default, meaning their value cannot change once set.
let x = 5; // x = 6; // This will cause a compile error because x is immutable.
Result
The program compiles and runs, but trying to change x causes an error.
Understanding that variables are immutable by default helps prevent accidental changes and bugs.
2
FoundationMaking variables mutable
🤔
Concept: You can make a variable mutable by adding the 'mut' keyword before its name.
let mut x = 5; x = 6; // This is allowed because x is mutable.
Result
The program compiles and runs, and x's value changes from 5 to 6.
Knowing how to declare mutable variables lets you change values safely when needed.
3
IntermediateMutable references and borrowing
🤔Before reading on: Do you think you can have multiple mutable references to the same variable at the same time? Commit to your answer.
Concept: Rust allows mutable references to variables but enforces rules to prevent data conflicts.
let mut x = 10; let r1 = &mut x; // let r2 = &mut x; // Error: cannot borrow x as mutable more than once at a time *r1 += 5; println!("{}", x); // Prints 15
Result
The program prints 15, but trying to create two mutable references causes a compile error.
Understanding Rust’s borrowing rules prevents bugs from simultaneous changes to the same data.
4
IntermediateShadowing mutable variables
🤔Before reading on: Can you declare a new variable with the same name as a mutable one to change its value without mut? Commit to your answer.
Concept: Rust allows shadowing, where a new variable with the same name replaces the old one, even changing mutability.
let mut x = 5; let x = x + 1; // x is now immutable with value 6 // x = 7; // Error: x is immutable now println!("{}", x); // Prints 6
Result
The program prints 6, and trying to change x after shadowing causes an error.
Knowing shadowing lets you change variable mutability and value safely without confusion.
5
AdvancedWhy Rust enforces explicit mutability
🤔Before reading on: Do you think making all variables mutable by default would make Rust safer or more error-prone? Commit to your answer.
Concept: Rust requires explicit mutability to help catch bugs at compile time and make code intentions clear.
In many languages, variables are mutable by default, which can lead to unexpected changes and bugs. Rust’s design forces you to think about which variables should change, improving safety and readability.
Result
Programs are safer and easier to understand because changes to data are intentional and visible.
Understanding this design choice explains why Rust code is often more reliable and easier to maintain.
6
ExpertMutable variables and interior mutability
🤔Before reading on: Can you change data inside an immutable variable in Rust using special types? Commit to your answer.
Concept: Rust provides special types like RefCell and Mutex that allow changing data inside an immutable variable safely at runtime.
use std::cell::RefCell; let x = RefCell::new(5); * x.borrow_mut() = 10; println!("{}", x.borrow()); // Prints 10 // This works even though x is not declared mutable.
Result
The program prints 10, showing data inside an immutable variable changed safely.
Knowing about interior mutability reveals how Rust balances safety with flexibility in complex programs.
Under the Hood
Rust’s compiler enforces mutability rules at compile time by tracking variable declarations and references. When you declare a variable as mutable, the compiler allows its memory location to be updated. For references, Rust uses borrowing rules to ensure only one mutable reference or multiple immutable references exist at a time, preventing data races. Interior mutability types use runtime checks to allow mutation inside immutable containers safely.
Why designed this way?
Rust was designed to prevent common bugs like data races and unexpected changes by making mutability explicit. This approach contrasts with many languages where mutability is implicit, leading to hidden bugs. The tradeoff is a steeper learning curve but much safer and more predictable code.
┌───────────────┐
│ let mut x = 5 │
│ Mutable var   │
│ Memory slot   │
│ Value: 5      │
└──────┬────────┘
       │
       ▼
┌───────────────┐
│ &mut x        │
│ Mutable ref   │
│ Exclusive     │
└───────────────┘

Rules:
- Only one &mut at a time
- Or many & (immutable refs)
- Compiler enforces this

Interior mutability:
┌───────────────┐
│ RefCell<T>    │
│ Runtime check │
│ Allows mut    │
└───────────────┘
Myth Busters - 3 Common Misconceptions
Quick: Do you think declaring a variable as mutable means it can be changed anywhere without restrictions? Commit to yes or no.
Common Belief:If a variable is mutable, you can change it freely anywhere in the code.
Tap to reveal reality
Reality:Rust restricts mutable access to one place at a time through borrowing rules, preventing simultaneous changes.
Why it matters:Ignoring borrowing rules leads to compile errors and misunderstanding how Rust ensures safety.
Quick: Do you think shadowing a mutable variable keeps it mutable? Commit to yes or no.
Common Belief:Shadowing a mutable variable keeps the new variable mutable automatically.
Tap to reveal reality
Reality:Shadowing creates a new variable that can be immutable or mutable depending on its declaration.
Why it matters:Assuming mutability carries over can cause unexpected compile errors when trying to change shadowed variables.
Quick: Do you think interior mutability breaks Rust’s safety guarantees? Commit to yes or no.
Common Belief:Using interior mutability types like RefCell is unsafe and breaks Rust’s safety rules.
Tap to reveal reality
Reality:Interior mutability uses runtime checks to maintain safety while allowing mutation inside immutable variables.
Why it matters:Misunderstanding this can lead to avoiding powerful Rust features or misusing unsafe code.
Expert Zone
1
Mutable variables in Rust are not just about changing values but about expressing intent clearly to the compiler and other developers.
2
The borrowing rules around mutability prevent data races at compile time, a unique feature compared to many languages.
3
Interior mutability types provide controlled exceptions to mutability rules, enabling patterns like shared mutability in concurrent contexts.
When NOT to use
Avoid mutable variables when you want to guarantee data does not change, such as constants or configuration values. Use immutable variables or constants instead. For shared state in concurrency, prefer synchronization primitives like Mutex or atomic types over raw mutable variables.
Production Patterns
In real-world Rust code, mutable variables are used sparingly and locally to limit side effects. Shadowing is common to transform data while keeping variables immutable afterward. Interior mutability is used in complex data structures like caches or GUI state where controlled mutation is needed without breaking safety.
Connections
Functional programming immutability
Opposite approach to data change
Understanding Rust’s explicit mutability helps appreciate how functional languages avoid mutable state to reduce bugs.
Concurrency and data races
Mutability rules prevent data races
Knowing Rust’s mutability and borrowing rules clarifies how it achieves safe concurrency without a garbage collector.
Database transactions
Controlled changes with safety guarantees
Like mutable variables with borrowing rules, transactions control when and how data changes to keep consistency.
Common Pitfalls
#1Trying to change an immutable variable
Wrong approach:let x = 5; x = 6; // Error: cannot assign twice to immutable variable
Correct approach:let mut x = 5; x = 6; // Allowed because x is mutable
Root cause:Not declaring the variable as mutable before trying to change its value.
#2Creating multiple mutable references simultaneously
Wrong approach:let mut x = 10; let r1 = &mut x; let r2 = &mut x; // Error: cannot borrow x as mutable more than once
Correct approach:let mut x = 10; let r1 = &mut x; // use r1 here // then create r2 after r1 is no longer used let r2 = &mut x;
Root cause:Violating Rust’s borrowing rules that allow only one mutable reference at a time.
#3Assuming shadowed variable keeps mutability
Wrong approach:let mut x = 5; let x = x + 1; x = 7; // Error: x is immutable now
Correct approach:let mut x = 5; let mut x = x + 1; x = 7; // Allowed because x is mutable
Root cause:Not realizing shadowing creates a new variable with its own mutability.
Key Takeaways
Rust variables are immutable by default to prevent accidental changes and bugs.
You must explicitly declare variables as mutable with 'mut' to change their values.
Rust’s borrowing rules restrict mutable references to one at a time to ensure safety.
Shadowing lets you replace variables and change their mutability, but you must declare it explicitly.
Interior mutability types allow safe mutation inside immutable variables using runtime checks.