Variables and Mutability
As mentioned in "Storing Values with Variables", by default, variables are immutable. This is one of many nudges Rust gives you to write your code in a way that takes advantage of the safety and easy concurrency that Rust offers. However, you still have the option to make your variables mutable. Let's explore how and why Rust encourages you to favor immutability and why sometimes you might want to opt out.
When a variable is immutable, once a value is bound to a name, you can't change that value. To illustrate this, generate a new project called variables in your project
directory by using cargo new variables
.
Then, in your new variables
directory, open src/main.rs
and replace its code with the following code, which won't compile just yet:
Filename: src/main.rs
fn main() {
let x = 5;
println!("The value of x is: {x}");
x = 6;
println!("The value of x is: {x}");
}
Save and run the program using cargo run
. You should receive an error message regarding an immutability error, as shown in this output:
$ cargo run
Compiling variables v0.1.0 (file:///projects/variables)
error[E0384]: cannot assign twice to immutable variable `x`
--> src/main.rs:4:5
|
2 | let x = 5;
| -
| |
| first assignment to `x`
| help: consider making this binding mutable: `mut x`
3 | println!("The value of x is: {x}");
4 | x = 6;
| ^^^^^ cannot assign twice to immutable variable
This example shows how the compiler helps you find errors in your programs. Compiler errors can be frustrating, but really they only mean your program isn't safely doing what you want it to do yet; they do not mean that you're not a good programmer! Experienced Rustaceans still get compiler errors.
You received the error message cannot assign twice to immutable variable
x`because you tried to assign a second value to the immutable
x` variable.
It's important that we get compile-time errors when we attempt to change a value that's designated as immutable because this very situation can lead to bugs. If one part of our code operates on the assumption that a value will never change and another part of our code changes that value, it's possible that the first part of the code won't do what it was designed to do. The cause of this kind of bug can be difficult to track down after the fact, especially when the second piece of code changes the value only sometimes. The Rust compiler guarantees that when you state that a value won't change, it really won't change, so you don't have to keep track of it yourself. Your code is thus easier to reason through.
But mutability can be very useful, and can make code more convenient to write. Although variables are immutable by default, you can make them mutable by adding mut
in front of the variable name as you did in Chapter 2. Adding mut
also conveys intent to future readers of the code by indicating that other parts of the code will be changing this variable's value.
For example, let's change src/main.rs
to the following:
Filename: src/main.rs
fn main() {
let mut x = 5;
println!("The value of x is: {x}");
x = 6;
println!("The value of x is: {x}");
}
When we run the program now, we get this:
$ cargo run
Compiling variables v0.1.0 (file:///projects/variables)
Finished dev [unoptimized + debuginfo] target(s) in 0.30s
Running `target/debug/variables`
The value of x is: 5
The value of x is: 6
We're allowed to change the value bound to x
from 5
to 6
when mut
is used. Ultimately, deciding whether to use mutability or not is up to you and depends on what you think is clearest in that particular situation.