</>
Skip to content
Rust lessons (7/43)

Rust — Variables

Variables are immutable by default

The single most surprising line for newcomers:

let x = 5;
x = 6;    // ❌ COMPILE ERROR: cannot assign twice to immutable variable

Rust makes immutability the default so the compiler (and readers) can assume values don't change unless declared otherwise. Opt into change explicitly:

let mut x = 5;    // mut = mutable
x = 6;            // ✓ fine now

Read let mut x as "I intend to change this." If you declare mut and never change it, the compiler warns you — defaults keep code honest.

Type inference — annotations usually optional

let count = 10;          // inferred as i32
let price = 9.99;        // inferred as f64
let name = "Ada";        // &str

let ratio: f32 = 0.25;   // annotation needed when default differs

Annotate when the compiler can't guess (parsing, empty collections) or for public function signatures:

fn parse_count(text: &str) -> i32 {
    text.trim().parse().expect("not a number")
}

Shadowing — new binding, same name

let spaces = "   ";            // string
let spaces = spaces.len();     // number — completely legal

Shadowing creates a new variable; the old one is gone but unchanged. This enables idiomatic transformation chains:

let input = "  42  ";
let input = input.trim();
let input: i32 = input.parse().expect("number");
// 'input' always holds the most meaningful form of itself

Contrast with mut, which cannot change type:

let mut spaces = "   ";
spaces = spaces.len();   // ❌ expected &str, found usize

Constants — compile-time and UPPERCASE

const MAX_POINTS: u32 = 100_000;

fn main() {
    println!("limit: {}", MAX_POINTS);
}
letconst
Value fixed atruntimecompile time
Type annotationoptionalrequired
Can shadowyesno
Usable outside functionsnoyes (global scope)

Naming convention: UPPER_SNAKE_CASE with underscores as thousand separators.

Scope — curly braces rule

{
    let inner = 42;
    println!("{}", inner);   // ✓ alive here
}
// println!("{}", inner)     // ❌ out of scope

Variables die at their closing brace; memory is freed automatically at that moment (this is ownership working).

Unused variables warn

let unused = 3;       // ⚠ warning: unused variable
let _ignored = 4;     // underscore prefix silences it deliberately
let _ = some_result;  // bare underscore: explicitly discard

Mini Practice

  1. Trigger the immutable-assignment error; fix with mut.
  2. Shadow a string through trim → parse → int in three lets.
  3. Try to change a mut string's type; read the error.
  4. Declare a const with underscore separators; print it.
  5. Create an unused variable, then silence it both ways.

Next: data types →

Related Topics

Frequently Asked Questions about Variables

What is Variables in Rust?

Variables is a fundamental concept in Rust. This lesson explains it step by step with clear examples, making it easy for beginners to understand.

How do I learn Variables?

Start by reading the explanation above, then try the code examples. Practice by modifying the examples and experimenting with different values. Hands-on practice is the best way to learn Variables.

Why is Variables important in Rust?

Variables is essential for Rust development. Understanding this concept will help you write better code and solve real-world problems more effectively.