Mutability & Shadowing

Mutability

This code will not compile:

let x = 0; x = 1;

The let keyword in Rust works a bit like how the const keyword works in JavaScript, in that all identifiers it declares are immutable. In JavaScript, const identifiers simply cannot be reassigned, but its properties can still be changed. In Rust, immutability is total: no reassignments, and no mutation of contents either. You could say it’s like const + [Object.freeze](<https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/freeze>) in JavaScript.

This seems like a pretty stringent limitation at first. However, there’s an escape hatch: the mut keyword. Actually, if you’ve been following along and trying out the code examples, you’ll already know about it—here’s the error message you’d get if you tried to compile the above example:

error[E0384]: cannot assign twice to immutable variable x --> src\\main.rs:4:5 | 3 | let x = 0; | - | | | first assignment tox | help: consider making this binding mutable:mut x` 4 | x = 1; | ^^^^^ cannot assign twice to immutable variable

For more information about this error, try rustc --explain E0384.`

Do you see it? The Rust compiler itself suggests a way to fix our code by using the mut keyword!

Having to use a whole additional keyword just to make a variable mutable may seem kind of inconvenient at first. However, immutable-by-default variable declarations make it easier for you to let the compiler make certain guarantees about your code, which can help detecting bugs early, for instance.

Shadowing

You may have noticed that a previous example re-bound the my_tuple identifier a second time using the let keyword. If we were to do something like this in a language like JavaScript, we’d get an error:

Uncaught SyntaxError: redeclaration of let my_tuple

In Rust, however, this is allowed. It simply defines another (new, discrete) identifier that just happens to shadow (override the name of) another identifier.

This can be useful when you wish to change the type or mutability of an identifier.

Scoping

Identifiers in Rust are block-scoped, meaning that an identifier declared within a set of curly braces {} is inaccessible outside of the braces.

fn main() { let x = 0; { // yonly exists in this scope let y = 1; println!("{} {}", x, y); } // scope ends println!("{} {}", x, y); //y is out of scope }

Output:

error[E0425]: cannot find value yin this scope --> src/main.rs:7:26 | 7 | println!("{} {}", x, y); //yis out of scope | ^ help: a local variable with a similar name exists:x``

Last updated