Immutability by default is the first place Rust pushes you toward code that is easier to reason about.
let introduces a binding. Bindings are immutable by default: once let x = 5; runs, assigning x = 6 is a compile error. To allow changes, say so with let mut x = 5;. This makes every place that mutates state visible at the declaration.
Types are inferred from usage, so annotations are optional in most local code: let count: u32 = 0; is the same as let count = 0u32;. When inference cannot decide (for example parsing a string), the compiler asks you to annotate.
Shadowing means declaring a new variable with the same name: let x = x + 1;. Unlike mut, it creates a fresh binding, so you can even change the type, which is handy for transforming input step by step (let input = input.trim();). The old value still exists until the end of its scope but is no longer reachable by that name.
const declares a compile-time constant. It always needs a type, is written in SCREAMING_SNAKE_CASE, and can live at module level: const MAX_USERS: usize = 1_000;. A static is similar but has one fixed memory address for the whole program; prefer const unless you need that address.
A binding must be initialised before use, but not necessarily at the let: the compiler tracks definite initialisation, so let x; if c { x = 1 } else { x = 2 } is fine. Unused variables produce warnings; prefix them with _ to silence the warning on purpose.
Example
const MAX_RETRIES: u32 = 3;
fn main() {
let attempts = 0;
// attempts += 1; // error: cannot assign twice to immutable variable
let mut tries = attempts;
tries += 1;
let input = " 42 ";
let input = input.trim(); // shadow: still &str
let input: i32 = input.parse().unwrap(); // shadow: now i32
println!("{tries}/{MAX_RETRIES}, value = {input}"); // 1/3, value = 42
}Remember
- Bindings are immutable unless declared
let mut - Shadowing creates a new binding and may change the type
constneeds a type annotation and is evaluated at compile time
Watch out for
- Reaching for
mutwhen shadowing (a transformed, immutable value) expresses the intent better.