Skip to content

Rust Variables

A variable is just a name you give to a value so you can use it later. Think of it as a labelled box: you put something in the box, write a name on it, and refer to it by that name instead of repeating the value everywhere.

In Rust you create a variable with the let keyword:

fn main() {
let age = 30;
println!("My age is {age}");
}

Output:

My age is 30
▶ Try it Yourself

Let’s break that line down:

  • let — tells Rust “I’m creating a new variable.”
  • age — the name we chose.
  • = — assigns the value on the right to the name on the left.
  • 30 — the value we’re storing.

The {age} inside println! prints the variable’s value. This is called string interpolation — Rust swaps {age} for whatever age holds.

Every value in Rust has a type (a whole number, text, true/false, and so on). You might expect to declare that type, but usually you don’t have to — Rust looks at the value and works it out. This is called type inference.

fn main() {
let score = 95; // Rust infers this is an integer
let name = "Ferris"; // Rust infers this is text
let is_active = true; // Rust infers this is a boolean
println!("{name}: {score}, active = {is_active}");
}

If you ever want to be explicit, you can write the type after a colon:

let score: i32 = 95; // i32 = a 32-bit integer

Here’s the part that surprises people coming from other languages: in Rust, once you set a variable, you can’t change it by default. “Immutable” just means cannot be changed.

This code will not compile:

fn main() {
let count = 1;
count = 2; // ❌ error: cannot assign twice to immutable variable
println!("{count}");
}

The compiler stops you with a clear message:

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

Why would a language do this on purpose? Because a lot of bugs come from values changing when you didn’t expect them to. By making things unchangeable unless you ask for change, Rust makes your code more predictable. It’s a feature, not a limitation.

When you genuinely need a value to change, add the mut keyword (short for mutable = changeable):

fn main() {
let mut count = 1;
println!("Before: {count}");
count = 2; // ✅ allowed now, because of `mut`
println!("After: {count}");
}

Output:

Before: 1
After: 2
▶ Try it Yourself

Rust lets you declare a new variable with the same name as an old one. This is called shadowing — the new one “casts a shadow” over the old one:

fn main() {
let x = 5;
let x = x + 1; // a new x, based on the old x -> 6
let x = x * 2; // another new x -> 12
println!("x is {x}");
}

Output:

x is 12
▶ Try it Yourself

This looks similar to mut, but it’s different:

  • mut changes the same variable’s value.
  • Shadowing creates a brand new variable that happens to reuse the name — and it can even be a different type.

Shadowing is handy when you want to transform a value but keep using the same name:

fn main() {
let spaces = " "; // text
let spaces = spaces.len(); // now a number (how many spaces)
println!("Number of spaces: {spaces}");
}

A constant is a value that never changes and is fixed at compile time. You declare it with const instead of let, and you must write the type:

const MAX_SCORE: u32 = 100;
fn main() {
println!("The maximum score is {MAX_SCORE}");
}

By convention, constants are written in UPPER_SNAKE_CASE. Here’s how they compare to regular variables:

let variable const constant
Can change? Only with mut Never
Type required? Optional (inferred) Required
Naming style snake_case UPPER_SNAKE_CASE
Where allowed Inside functions Anywhere, even outside functions

Use a constant for values that are truly fixed — like the number of seconds in a minute, or a maximum limit.

  • Use snake_case — lowercase words joined by underscores: user_name, total_price.
  • Names can contain letters, numbers, and underscores, but can’t start with a number.
  • Choose descriptive names: age is better than a.
  • Create variables with let; Rust usually infers the type for you.
  • Variables are immutable by default — add mut to allow changes.
  • Shadowing re-declares a name with let, creating a new variable (can change type).
  • Constants (const) never change, always need a type, and use UPPER_SNAKE_CASE.

Quick check

1. By default, can you reassign a `let` variable in Rust?

2. What is shadowing in Rust?

3. Which naming convention do Rust variables use, according to this page?

Score: 0 / 3