Welcome to our next lesson. In our previous session, we established the critical distinction between statements (which perform actions) and expressions (which evaluate to a value). We saw that let x = 5; is a statement. Today, we'll examine this let binding more closely to uncover one of Rust's core design philosophies: immutability.
This lesson will explain how to declare variables and, more importantly, why Rust treats them as immutable by default. We'll explore how to explicitly make variables mutable when needed and discuss the rationale behind this design choice. For someone with your background in Python and Swift, where variables are generally mutable by default, this will be a key point of differentiation and a significant step toward understanding Rust's focus on safety and predictability.
1. Immutability: The Default State
In Rust, when you declare a variable using the let keyword, you are creating a binding that is immutable. This means that once a value is bound to a name, you cannot change that value.
Let's start by reading the official explanation from "The Rust Programming Language" book, which demonstrates this concept with a code example that will intentionally fail to compile.
Variables and Mutability - The Rust Programming Language
This section from the official Rust book introduces the concept of variables being immutable by default and explains the safety benefits of this design.
Please read the first part of the chapter, from the beginning. Pay close attention to the example code, the resulting compiler error, and the book's explanation for why this compile-time check is a feature, not just a frustration.
The error message you just read about is central to understanding Rust's approach. You tried to assign a second value to an immutable variable, and the compiler stopped you. This isn't a limitation; it's a safety guarantee.
Here is a screenshot of what that error looks like in a terminal. Notice how clear and helpful the compiler's message is.

Why would Rust enforce this? The book touches on it, but the core idea is to reduce cognitive overhead and prevent entire classes of bugs. When you know a value cannot change, you can reason about your code with greater certainty. This is especially true in complex programs where a value might be passed through many functions. If a value is immutable, you don't need to track whether one of those functions might have changed it unexpectedly.
2. Opting into Mutability with mut
Of course, we often need variables that can change. Rust provides a clear and explicit way to do this using the mut keyword. By adding mut before a variable name, you are signaling to both the compiler and to anyone reading your code that this variable's value is expected to change.
Let's see how to fix the previous example. The following short video provides a great visual demonstration of both the problem and the solution.
Rust's MUTABILITY system is a Game Changer | Rust Fundamentals Part 3
This video from the Green Tea Coding channel concisely demonstrates the default immutability and how to enable mutability.
Please watch from the introduction of variables. The presenter will: Declare a variable and attempt to reassign it, triggering the compiler error. Introduce the mut keyword to make the variable mutable, allowing the code to compile and run successfully.
As the video explains, immutability is an "opt-out" feature in Rust. This is the reverse of many languages, including Python and Swift (where you might use var for mutable and let for immutable). In Rust, let on its own means immutable, and you must explicitly "opt-in" to mutability with let mut.
You can see the corrected code in the official Rust book as well.
Variables and Mutability - The Rust Programming Language
This section provides the working code example using the mut keyword.
Read the short section that begins with this paragraph to see the final, compiling version of the code.
3. The Philosophy: Readability and Intent
This design choice—immutability by default—is not arbitrary. It's a cornerstone of Rust's philosophy, aimed at making code safer and easier to understand. When you see let mut, it acts as a signpost, immediately drawing your attention to a piece of state that can change.
For a high-level perspective on why this is so valuable, let's hear from two experienced programmers.
Rust programming language explained | ThePrimeagen and Lex Fridman
In this clip from a discussion with Lex Fridman, developer ThePrimeagen explains the practical benefit of explicit mutability.
Watch the short segment from this timestamp. The key takeaway is how mut improves code readability by making it obvious which parts of your program's state can change.
By forcing you to be explicit with mut, Rust makes you pause and think, "Do I really need this variable to change?" This small moment of friction encourages a style of programming that often leads to more robust and maintainable code.
To explore this philosophy further, the following article provides an excellent summary.
Aim For Immutability in Rust - Corrode.dev
This blog post by Matthias Endler offers a compelling argument for why immutability is a powerful default.
Please read the three subsections under the main Summary heading. The key ideas are that immutable code is easier to reason about and that Rust's approach pushes you toward better habits.
4. A Quick Note on Constants
You may also encounter the const keyword in Rust. While both immutable variables and constants hold values that cannot be changed, they have a few key differences:
- You must always annotate the type of a
const. - You declare them with
constinstead oflet, and you are not allowed to usemutwith them. They are always immutable. - A
constcan only be set to a constant expression that can be evaluated at compile time, not a value that can only be computed at runtime. For example,const PI: f64 = 3.14159;is valid, but the result of a function call is not. - Constants can be declared in any scope, including the global scope.
For now, the key distinction to remember is that let bindings can be immutable or mutable, while const bindings are always immutable and more restrictive.
Conclusion
In this lesson, we explored a fundamental aspect of Rust's design: its preference for immutability. This is one of the primary "nudges" the language gives you to write safer, more predictable code.
Here are the key takeaways:
- Variables declared with
letare immutable by default. Once a value is bound, it cannot be reassigned. - To create a mutable variable, you must explicitly use the
let mutsyntax. - This "immutability-by-default" philosophy is a deliberate design choice that enhances code safety and readability by making state changes explicit.
- This approach contrasts with languages like Python and Swift, where variables are typically mutable by default.
In our next lesson, we will look at a related concept called shadowing. This allows you to declare a new variable with the same name as a previous one, which is subtly but importantly different from mutating an existing variable.