lesson 2 of N · rust fluency
variables and mutability
in most languages, variables are mutable by default. in rust, they are immutable. this is not a quirk; it is a safety guarantee that allows the compiler to optimize your code and prevent data races.
the default: immutable
when you declare a variable with let, you cannot change its value. this is the default state.
fn main() {
let x = 5;
x = 6; // ERROR: cannot assign twice to immutable variable `x`
}
opting into mutability
if you need to change a value, you must explicitly mark the variable as mutable using the mut keyword. this tells anyone reading the code (and the compiler) that this value will change.
fn main() {
let mut x = 5;
println!("the value is: {x}");
x = 6;
println!("the value is now: {x}");
}
by forcing you to be explicit about mutability, rust makes it easier to reason about state. if you see
let x, you know x will never change. if you see let mut x, you know to watch for state changes.
shadowing: the alternative to mutability
sometimes you want to change a value but keep it immutable. rust allows shadowing: declaring a new variable with the same name as a previous one. this effectively replaces the old variable.
fn main() {
let spaces = " "; // a string
let spaces = spaces.len(); // now an integer (usize)
println!("number of spaces: {spaces}");
}
shadowing differs from mutability in two ways:
- you can change the type of the variable.
- the resulting variable remains immutable.
do it now
- create a new crate:
cargo new mutability - try to change an immutable variable and read the compiler error.
- fix it using
mut. - try shadowing a string into an integer using
spaces.len().
check yourself
primary source
read chapter 3.1 of the Rust Book, variables and mutability. it explains the nuance between shadowing and mutability in detail.
stuck on mut vs shadowing? ask. it's one of the first mental shifts when moving to rust.