Back to Blog

[Rust] Understanding Variables and Mutability

(edited: March 12, 2026)

Hello! Today, we are going to explore the very basics of Rust programming: variables and mutability. Rust handles variables in a unique way compared to many other languages, and this specific behavior is a key part of what makes Rust so safe and powerful.

Variables are Immutable by Default

In Rust, when you declare a variable using the let keyword, it is immutable by default. This means that once a value is bound to a name, you cannot change that value.

Let’s try writing some code like this:

Rust
fn main() {
    let x = 5;
    println!("The value of x is: {x}");
    x = 6; // An error occurs here!
    println!("The value of x is: {x}");
}

If you run this code, the Rust compiler will throw an error: cannot assign twice to immutable variable x.

Why was it designed this way? The reason is safety. If one part of your code assumes a value will never change while another part quietly changes it, it can lead to bugs that are incredibly hard to track down. Rust prevents this right at the compilation stage.

Using the mut Keyword for Mutability

Of course, there are plenty of situations where you need to change a value. In those cases, you can make a variable mutable by adding the mut keyword.

Rust
fn main() {
    let mut x = 5;
    println!("The value of x is: {x}");
    x = 6; // Now this is allowed!
    println!("The value of x is: {x}");
}

Using mut also serves as a clear signal to the compiler and your future self (or colleagues) that this variable’s value will be changing later in the code.

Differences Between Constants and Variables

While they might seem similar to immutable variables, Constants are even more strict. They are declared with the const keyword and have a few key differences:

  • You can never use mut with a constant. They are always immutable.
  • You must explicitly annotate the type (e.g., u32).
  • They cannot be set to a value computed at runtime; they must be set to a constant expression that the compiler can evaluate.
Rust
const THREE_HOURS_IN_SECONDS: u32 = 60 * 60 * 3;

Constants are useful for fixed values that don't change throughout the life of the program (like a maximum score in a game or the speed of light). By convention, they are written in all uppercase with underscores.

Shadowing

Rust has an interesting concept called Shadowing. This allows you to declare a new variable with the same name as a previous one.

Rust
fn main() {
    let x = 5;
    let x = x + 1; // Shadows the first x and creates a new one.

    {
        let x = x * 2; // A new x valid only within this inner scope
        println!("The value of x in the inner scope is: {x}"); // 12
    }

    println!("The value of x is: {x}"); // 6
}

Shadowing vs mut

Shadowing is different from using mut for two main reasons:

  1. Maintaining Immutability: Since we use the let keyword again, the variable remains immutable after we are done with our transformations.
  2. Changing Types: Unlike mut, which only allows you to change the value, shadowing allows you to effectively change the type of the value while reusing the same name.
Rust
// Type transformation using shadowing (Allowed)
let spaces = "   "; // String type
let spaces = spaces.len(); // Reborn as a numeric type!

If you tried this with mut, the compiler would complain that you are trying to change a variable's type.

Summary

  1. Immutability: Rust variables are immutable by default when declared with let.
  2. Mutability: Use let mut if you need to change the value.
  3. Constants: const is always immutable and requires a type annotation.
  4. Shadowing: You can redeclare a variable with the same name to transform values or change types.

Comments