Lesson 2.2 · 8 min
Values that change
A chat program has to count: how many messages so far. A count that cannot change is not much of a count. Rust makes you ask before a name may change, and the compiler explains what happens if you forget.
Adds to ChatterboxA message counter.
Try to change a name
Chatterbox should say how many messages have been sent. Start the count at zero and add one when a message arrives. Here is the obvious way to write it.
error[E0384]: cannot assign twice to immutable variable `message_count` --> src/main.rs:3:5 | 2 | let message_count = 0; | ------------- first assignment to `message_count` 3 | message_count = message_count + 1; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ cannot assign twice to immutable variable | help: consider making this binding mutable | 2 | let mut message_count = 0; | +++
Read the message. "cannot assign twice to immutable variable" says it plainly. Immutable means "cannot change". A plain let gives a name that is set once. The compiler even suggests the fix in its help text: make it mutable.
This is a safety feature, not a nuisance. In a long program, a value that can change anywhere is a value you cannot trust anywhere. So Rust starts every name as fixed, and you opt in to change, one name at a time, with the word mut (short for "mutable").
$ cargo run
2 messages so farWhat does this print?
121510
Reveal the answer
The program prints: 12 Each assignment uses the current value. 10 becomes 15, then 15 becomes 12. The name count only ever holds the latest value.
A shortcut, and a different trick
count = count + 1 is so common it has a short form: count += 1. Same meaning, fewer characters.
There is also a second way to "change" a name that is not changing at all. You can write let again with the same name. This is called shadowing: the new name sits in front of the old one and hides it. The old value is untouched; you just cannot reach it by that name any more.
$ cargo run
20Which to use? Reach for let mut when one thing really is a running tally, like a counter. Reach for shadowing when you are working a value through steps and the old version is no longer interesting. A rule of thumb: start with plain let, and add mut only when the compiler asks.
Chatterbox v0.2, step two
The counter goes in. It starts at zero, and one message is counted.
$ cargo run
Chatterbox v0.2
Hi Sam! I'm Chatterbox.
1 messages so farMake count_after return the starting count plus the number of new messages. i32 is just "a whole number"; the next lesson explains it. Start from the let mut line already there. You don't need to understand fn yet (chapter 3, lesson 4 explains it): just fill in the body.
Make count_after return the starting count plus the number of new messages. i32 is just "a whole number"; the next lesson explains it. Start from the let mut line already there. You don't need to understand fn yet (chapter 3, lesson 4 explains it): just fill in the body.
Hidden tests (3): adds_to_existing from_zero nothing_arrives
This exercise runs real Rust in your browser through the official Rust Playground, so it needs JavaScript.
Say it out loud, then reveal
What does E0384 mean?Reveal
How do you allow a name to change?Reveal
What is the difference between mut and shadowing?Reveal
That is lesson 2.2. Tick it off so the course remembers where you are.
Questions people ask
Why is Rust immutable by default?
A value that cannot change is easier to trust when reading code. You opt in to change only where you need it.
What does mut stand for?
Mutable, which means able to change.
Is shadowing the same as changing a variable?
No. It creates a new name. The old value still exists until it goes out of scope.