Skip to content

Beginner · Getting started with Rust · topic 4 of 50 · 25 min

Variables, mutability, shadowing and constants

Explanation

let creates a variable, and in Rust variables cannot change unless you add mut. Shadowing means declaring a new variable with the same name, which can even change the type. const makes a constant that never changes, with a written type and an UPPER_CASE name.

Why are variables fixed by default?

A variable is a name for a value. In most languages, any line can change any variable. In a large program that causes bugs: a value changes somewhere far away and you cannot find where. Rust makes variables immutable by default. Immutable means "cannot be changed". If you want a variable to change, you must say so with mut. Then anyone reading the code knows exactly which values move.

rust
fn main() {
    let price = 100;
    price = 120; // error[E0384]: cannot assign twice to immutable variable
}
This does not compile. The compiler suggests: consider making this binding mutable: mut price.
rust
fn main() {
    let mut price = 100;
    println!("Old price: {price}");
    price = 120;
    println!("New price: {price}");
}
With mut the value can change. Prints: Old price: 100, then New price: 120.
Think of it like this: An immutable variable is like a printed price tag: once printed, it stays. A mut variable is like a price written on a small whiteboard: you are allowed to wipe it and write a new number, and everyone can see it is a whiteboard.

Types are fixed, even with mut

mut lets the value change, but not the type. A type is the kind of value: a whole number, a decimal number, text and so on. Rust works out the type from the first value; this is called type inference. You can also write the type yourself after a colon.

rust
let mut count: i32 = 5;
count = 6;        // fine: still a number
// count = "six"; // error: expected i32, found &str
i32 is a 32-bit whole number. You will meet all the types in the next module.

Shadowing

Shadowing means writing let again with the same name. This creates a brand-new variable that hides the old one. It is useful when you transform a value step by step, and it can even change the type.

rust
fn main() {
    let input = "  42  ";
    let input = input.trim();          // still text, without spaces
    let input: i32 = input.parse().unwrap(); // now a number
    println!("{}", input + 1);
}
Prints 43. Each let makes a new variable; the old one is hidden. parse turns text into a number; unwrap is explained in module 6.
let mut xlet x again (shadowing)
Creates a new variable?No, changes the same oneYes
Can change the type?NoYes
Result is mutable?YesOnly if you write let mut

Shadowing also works inside a block (code in curly braces). The inner variable exists only until the closing brace; after it, the outer one is visible again.

rust
let x = 5;
{
    let x = x * 2;
    println!("inside: {x}");  // inside: 10
}
println!("outside: {x}");     // outside: 5
The inner x lives only inside the braces.

Constants

A constant is a value fixed for the whole program, like a GST rate or the number of seconds in a day. Write it with const, an UPPER_CASE name, and the type is required. Its value must be known when the program is compiled, so it cannot come from user input.

rust
const GST_PERCENT: u32 = 18;
const SECONDS_PER_DAY: u32 = 24 * 60 * 60;

fn main() {
    let price = 500;
    println!("GST: {}", price * GST_PERCENT / 100);
}
Prints GST: 90. u32 is a whole number that cannot be negative. Constants can be declared outside any function.

There is also static, a value with one fixed place in memory for the whole run. You will rarely need it as a beginner; prefer const.

Names and warnings

  • Variables and functions use snake_case: total_price, not totalPrice.
  • Constants use SCREAMING_SNAKE_CASE: MAX_USERS.
  • An unused variable gives a warning. Start its name with an underscore (_temp) if it is unused on purpose.

Common mistakes

  • Adding mut everywhere "just in case". The compiler warns "variable does not need to be mutable". Remove mut when the value never changes.
  • Trying to change the type of a mut variable. Use shadowing with a new let instead.
  • Writing const without a type, like const RATE = 18;. Add the type: const RATE: u32 = 18;.
  • Confusing shadowing with changing: after let x = x + 1; inside a block, the outer x is unchanged.

Need help?

Stuck on a word or an idea? Search this course, or every course, and jump straight to the explanation or a worked question.

Try:

Watch the lesson

Variables, mutability, shadowing and constants · 1/7

let = fixed let mut = can change

Variables in Rust have one surprise: they cannot change unless you ask.

Prefer a video by a teacher? Find free videos on “rust variables mutability shadowing constants explained” on YouTube ↗

In real life: Cleaning a mobile number from a form

A signup form for a food delivery app gets a mobile number as text with spaces and a +91 prefix. The code shadows the same name step by step: trim the spaces, remove the prefix, then check that 10 digits remain. Each step makes a new, immutable variable, so no later line can change the value by accident.

rust
fn main() {
    let phone = " +91 9876543210 ";
    let phone = phone.trim();
    let phone = phone.trim_start_matches("+91").trim();
    println!("{phone} has {} digits", phone.len());
}
Prints: 9876543210 has 10 digits

Practice (0/3 done)

Task 1 · Question

What does this print? fn main() { let x = 3; let x = x * 2; { let x = x + 1; println!("{x}"); } println!("{x}"); }

Task 2 · Question

Which change makes this compile? fn main() { let total = 0; total = total + 50; }

Task 3 · Practice

Write a program for a mobile recharge: a constant for GST (18%), a mut variable for the wallet balance that starts at 500, then subtract a recharge of 199 plus GST and print the new balance. Then use shadowing to turn the text " 2 " into the number 2 and print it doubled.

Quick quiz

Question 1

1.By default, a Rust variable created with let is…

Question 2

2.Which can change a variable's type?

Question 3

3.Which constant is written correctly?

Question 4

4.What does the compiler say if you mark a variable mut but never change it?

Question 5

5.Which name follows Rust style for a variable?

Read more (free)

Open a question to see the answer and why. The first ones are this topic's own quiz, so try the quiz above before you peek.

By default, a Rust variable created with let is…

Answer: Immutable

Variables are immutable unless you write let mut.

Which can change a variable's type?

Answer: Shadowing with a new let

Shadowing creates a new variable, so the new one can have a different type.

Which constant is written correctly?

Answer: const RATE: u32 = 18;

A const needs a type and a value; the name is UPPER_CASE by convention.

What does the compiler say if you mark a variable mut but never change it?

Answer: A warning: variable does not need to be mutable

It is a warning, not an error. Remove mut to keep code clear.

Which name follows Rust style for a variable?

Answer: total_price

Variables and functions use snake_case. UPPER_CASE is for constants.

What is in an int variable declared inside main with int n; and no value?Related

Answer: Garbage: reading it is undefined behaviour

Local variables are not set to zero automatically. Always initialise them.

From Variables, types and constants

Which keyword should you use by default for new variables?Related

Answer: const

Use const by default and switch to let only when you must reassign.

From Variables: let, const and var

const int Max = 10; Max = 20; What happens?Related

Answer: Compile error: a const cannot be changed

A const value is fixed at compile time and cannot be assigned again.

From Types and variables

What is the first step of shadowing?Related

Answer: Listen once to understand the meaning

Understand the meaning first; then read along, then shadow.

From Shadowing and thinking in English

Pass the quiz (60% or more) or mark this topic as done when you are ready.

Your progress is saved on this device only.

Next steps

  1. This is the last topic of “Getting started with Rust”. The module exam comes next.
  2. Module 1 exam: Getting started with Rust · 12 questions · 20 min, without help. 4 topics of this module still to finish first.
  3. Then the next module, Types, control flow and functions. 50 topics left in the course before the final exam.

← Previous: Your first program and cargo