Rust Foundations·Ownership as a design tool

Variables and mutability

Rust bindings are immutable by default, so mut, shadowing and const keep change deliberate.

Intermediate 12 min read Lesson 1 of 300 Challenge included
What you will be able to do
  • Prefer immutable let bindings and reach for mut only when you need reassignment.
  • Use shadowing to transform a value and change its type under the same name.
  • Declare compile-time values with const and give them an explicit type.
  • Watch integer overflow: debug builds panic, so pick a wide enough type.

In plain English

A variable is declared with let, and in Rust a variable is immutable by default, which means once you give it a value you cannot change it. Adding mut makes a binding mutable so you can assign a new value later. Shadowing is declaring a variable again with the same name using a new let, which lets you reuse a name and even switch its type without ever mutating the original binding. Constants are declared with const, always need an explicit type and a value known at compile time, and are never mutable. The primitive types are signed and unsigned integers of several widths, floats, booleans and characters, and overflowing an integer in a debug build causes a panic, a controlled crash that stops the program instead of silently wrapping the number.

Step by step

  1. 1Declare a value with let and try to change it to feel the immutability rule.
  2. 2Add mut to a binding you need to reassign.
  3. 3Shadow a variable with a second let to reuse the name or change its type.
  4. 4Define a const with an explicit type and a compile-time value.
main.rsRust
fn main() {
    let title = "Variables and mutability";
    println!("{}", title);

    let mut minutes = 12;
    minutes = 14;
    println!("{} minutes", minutes);

    let rating = 4;
    let rating = rating + 1;
    let rating = rating as f64 + 0.5;
    println!("rating {}", rating);

    let price: f64 = 19.99;
    let published: bool = true;
    let grade: char = 'A';

    const MAX_LESSONS: u32 = 100;
    println!("{} {} {} {}", price, published, grade, MAX_LESSONS);
}

Common mistakes

  • Trying to reassign a plain let binding fails to compile, because let bindings are immutable by default.
  • Assuming const and let behave the same is wrong: const needs an explicit type and a compile-time value and cannot use mut.
  • Using a too-small integer type and then overflowing it panics in a debug build instead of silently wrapping.
  • Confusing shadowing with mutation is a slip: shadowing creates a new binding, so the original value still exists until it goes out of scope.
Your turn

Raise a score by shadowing

Easy

Declare an immutable score, then use shadowing to raise it by 10 and print the result.

RUST · starter
fn main() {
    let score = 90;
    println!("{}", score);
}
Check your understanding before moving on.
Knowledge checkQuestion 1

What happens if you try to reassign a value declared with plain let?

Select an answer to continue
Study tools

Make it yours.

Keep a private note for this lesson, then turn the key ideas into flashcards you can revisit.

Sign in to save notes and flashcards.Both are private to your account and stay with your progress.
Sign in
Finished reading?

Lock in what you just learned.

Mark this lesson complete to save your place and move one step closer to the certificate.

Lesson 1 of 300 · 0% of course