Flashcard Rust: Variables

A compact Rust flashcard about immutable bindings, mutable variables, and shadowing, with small programs and compiler output.
coding
rust
Author

unrahul

Published

March 16, 2020

The first thing that surprised me about Rust variables was that a plain let does not give me something I can freely reassign. Rust makes the safer choice the short choice.

Flashcard 03 Rust

The question

Why can’t I assign a new value to this variable?

Look at the binding. A plain let carries an important default.

Reveal the answer

Rust bindings are immutable by default. Add mut when the value must change, or use a new let when shadowing is what you mean.

Immutable by default

The keyword let creates a binding:

fn main() {
    let name = "unrahul";
    println!("name is {}", name);
}
name is unrahul

If I try to assign another value to name, the compiler stops me:

fn main() {
    let name = "unrahul";
    println!("name is {}", name);
    name = "rahul";
    println!("new name is {}", name);
}
error[E0384]: cannot assign twice to immutable variable `name`
  |
2 |     let name = "unrahul";
  |         ---- first assignment to `name`
3 |     name = "rahul";
  |     ^^^^^^^^^^^^^^ cannot assign twice to immutable variable

A useful compiler follow-up

Running rustc --explain E0384 gives a longer explanation of this exact error. The compiler error codes are worth following.

Make the binding mutable

When reassignment is actually part of the program, I can say so explicitly:

fn main() {
    let mut name = "unrahul";
    println!("name is {}", name);
    name = "rahul";
    println!("new name is {}", name);
}
name is unrahul
new name is rahul

The only change is let mut name. Anyone reading the code can now see that the binding may change.

Shadow the old binding

Shadowing creates a new binding with the same name:

fn main() {
    let name = "unrahul";
    println!("name is {}", name);

    let name = "rahul";
    println!("new name is {}", name);
}
name is unrahul
new name is rahul

That second let is not mutating the first binding. It creates a new one and shadows the old name. The new binding may even have a different type, which is one reason shadowing is not the same thing as mut.

What I keep in my head

Use mut when one binding changes value. Use another let when I want a new binding that happens to reuse the same name.