Rust Variables and Mutability

A variable is a named storage location in memory. You give it a name, store a value in it, and use that name later to read or change the value. Rust handles variables differently from most languages — by default, all variables are immutable, meaning you cannot change them after you set them.

Creating a Variable with let

Use the let keyword to create a variable:

fn main() {
    let age = 25;
    println!("My age is {}.", age);
}

Output:

My age is 25.

The variable age now holds the value 25. Rust figures out the type (integer) automatically — you do not have to write it yourself in simple cases.

Variables Are Immutable by Default

If you try to change the value of a variable after you create it, Rust refuses to compile:

fn main() {
    let age = 25;
    age = 30;   ← This causes a compiler error
}

The compiler shows this error:

error[E0384]: cannot assign twice to immutable variable `age`

Why Immutability by Default?

When a value cannot change, you can trust that it stays the same throughout your program. This prevents bugs where one part of your code accidentally changes a value another part depends on.

The Locked Box Diagram

let age = 25;

[ age ] = [ 25 ] ← Box is sealed. You can read it but not change it.

age = 30;  ← Compiler: "This box is locked. You cannot put 30 in it."

Making a Variable Mutable with mut

When you do need to change a variable, add the mut keyword:

fn main() {
    let mut score = 0;
    println!("Score: {}", score);
    score = 10;
    println!("Score after update: {}", score);
}

Output:

Score: 0
Score after update: 10

mut tells Rust this variable's value will change. Now the compiler allows reassignment.

The Unlocked Box Diagram

let mut score = 0;

[ score ] = [ 0 ] ← Box is open. You can put a new value in.

score = 10;  → [ score ] = [ 10 ] ← Value updated successfully.

Constants

A constant is a value that never changes and is known before the program runs. Use the const keyword to create one. Constants must always have a type written explicitly, and their names are written in ALL_CAPS by convention.

const MAX_SCORE: u32 = 100;

fn main() {
    println!("Maximum score is {}.", MAX_SCORE);
}

Difference Between let and const

Feature              let                    const
---------            ------                 ------
Can be mutable       Yes (add mut)          No — always fixed
Type annotation      Optional               Required
Computed at          Runtime                Compile time
Naming style         snake_case             UPPER_SNAKE_CASE
Scope                Inside functions       Anywhere in program

Shadowing

Shadowing lets you create a new variable with the same name as an existing one. The new variable "shadows" the old one — inside the current block, the old value is hidden.

fn main() {
    let number = 5;
    let number = number + 1;   ← New variable also named "number"
    let number = number * 2;   ← Another new variable named "number"
    println!("The number is {}.", number);
}

Output:

The number is 12.

Each let number = creates a fresh variable. The old one disappears from view.

Shadowing vs Mutability

Shadowing looks similar to mutability but works differently. With shadowing, you can change the type of the value. With mut, the type must stay the same.

let spaces = "   ";        ← spaces is a text value
let spaces = spaces.len(); ← spaces is now a number (shadowed)

let mut spaces = "   ";
spaces = spaces.len();     ← Compiler error: type mismatch

The Name Tag Diagram

First:   [ number ] → [ 5 ]
Second:  [ number ] → [ 6 ]   (old tag hidden, new tag with same name)
Third:   [ number ] → [ 12 ]  (hidden again)

Variable Naming Rules

Rust variable names follow these rules:

  • Start with a letter or underscore
  • Contain only letters, numbers, and underscores
  • Use snake_case style — all lowercase with underscores between words
  • Reserved keywords like fn, let, and mut cannot be used as names
let user_age = 30;       ← Good: snake_case
let userAge = 30;        ← Works but not Rust style
let 2fast = 10;          ← Bad: starts with a number
let fn = 5;              ← Bad: fn is a reserved keyword

Unused Variable Warning

Rust warns you when you create a variable but never use it. This helps catch typos and dead code.

fn main() {
    let name = "Alex";   ← Warning: unused variable `name`
}

To silence the warning on purpose, start the name with an underscore:

let _name = "Alex";   ← No warning

Quick Reference

let x = 5;          ← Immutable variable
let mut x = 5;      ← Mutable variable
const MAX: u32 = 100; ← Constant
let x = x + 1;     ← Shadowing (new x hides old x)

Leave a Comment