Rust Variables

Rust's `let` keyword binds values to names, and unlike most languages, those bindings are immutable unless you explicitly opt in to change.

#Jobseeker

Find matching jobs & Auto apply with AI

Hyring
Jobseeker using Hyring to search, apply, and prepare with AI

Declaring Variables with let

Every variable in Rust starts life with the `let` keyword. You don't need to declare a type up front in most cases -- the compiler infers it from the value you assign, and from how you use the variable afterward.

Basic Variable Declaration

fn main() {
    let language = "Rust";
    let year = 2015;
    println!("{} was first released around {}", language, year);
}

Immutability by Default

Once a value is bound with `let`, Rust will not let you change it. This is a deliberate design choice: immutable data is easier to reason about, safer to share across threads, and it eliminates a whole category of bugs where a variable changes value somewhere you didn't expect. Trying to reassign `language` above would fail to compile with an error pointing at the exact line.

Note: The compiler error for reassigning an immutable variable -- "cannot assign twice to immutable variable" -- appears at build time, not at runtime. You find out about the mistake before the program ever ships.

Opting Into Mutability with mut

When you genuinely need a variable to change -- a loop counter, a running total, a value read from user input -- add the `mut` keyword after `let`. This tells both the compiler and anyone reading the code that this binding is expected to change.

Using mut to Update a Value

fn main() {
    let mut score = 0;
    println!("Starting score: {}", score);

    score = score + 10;
    score += 5;

    println!("Final score: {}", score);
}

Shadowing: Rebinding Instead of Mutating

Rust also lets you declare a new variable with the same name as a previous one, using `let` again. This is called shadowing. Unlike `mut`, shadowing creates an entirely new binding -- which means the new value can even have a different type than the old one.

Shadowing to Change Type

fn main() {
    let spaces = "   ";
    let spaces = spaces.len();
    println!("That string had {} spaces", spaces);
}
  • `let` creates an immutable binding by default
  • `let mut` allows the same variable to be reassigned, but only to a value of the same type
  • Shadowing (`let` again) creates a brand-new variable, so the type is free to change
  • Shadowed variables are only visible from the point of shadowing onward within their scope
Note: Shadowing is scoped. If you shadow a variable inside a `{ }` block, the outer variable reappears unchanged once that block ends -- the shadow only applies inside it.
ApproachReassignable?Can change type?Keyword
`let`NoNolet
`let mut`YesNolet mut
ShadowingN/A -- new bindingYeslet (again)

Exercise: Rust Variables

By default, once a value is bound with `let`, can it be reassigned?