Lesson 2.7 · 8 min
Chapter review: Values
Chapter 2 gave Chatterbox things to remember: a name, a counter with a size, a length limit, a quiet switch, a greeting that grows and settings at the top of the file. Before it starts making decisions, check that it all holds together: a mixed quiz, then one bigger exercise that uses the whole chapter.
Adds to ChatterboxNothing new: a mixed quiz on the whole chapter, and a bigger exercise that uses all of it.
What chapter 2 gave you
Chatterbox v0.2 still does the same thing every time it runs, but it now knows things: its name and version live in one place, it counts with a number that says how big it can grow, and it has a limit and a switch ready for the moment it can decide. One line per lesson, each linked back:
- 2.1 Names for values:
let bot = "Chatterbox";says a value once, and every later use ofbotmeans it. A plainletis fixed for good. - 2.2 Values that change:
let mutopts in to change; assigning twice without it is E0384. Writingletagain with the same name is shadowing, a brand new name that hides the old one. - 2.3 Numbers and true/false:
i32,usizefor sizes,f64for decimals,boolfor yes or no. Whole-number division drops the fraction, and a comparison answerstrueorfalse. - 2.4 How big a number can get: every whole-number type has a largest value. Going past it panics while you work, and
saturating_addstops at the top on purpose. - 2.5 Text: a
&stris a view of text you can read; aStringis text you own and can grow withpush_str.len()counts bytes, not letters. - 2.6 Pairs and constants: a
constis a fixed fact the whole program can see, with a capital name and a stated type. A tuple keeps a few values together, read by position with.0and.1or pulled apart withlet (a, b).
Mixed quiz
Eight short programs, all new, with the chapter's ideas shuffled: a name, then text, then a number, then a pair, and round again. Some do not compile, one compiles and then stops while running, and the rest print something exact. Decide which kind each one is before you choose. Every answer was produced by the real compiler.
Does this compile — and if it does, does it run?
- It compiles and runs
- Compile error E0384
- It compiles, then panics
Reveal the answer
It does not compile: E0384. A name made with plain let is set once. Line 4 tries to give quiet a second value, so the compiler refuses with E0384, "cannot assign twice to immutable variable", and its help line suggests let mut quiet. Lesson 2.2 is the one to revisit.
error[E0384]: cannot assign twice to immutable variable `quiet` --> src/main.rs:4:5 | 2 | let quiet = false; | ----- first assignment to `quiet` 3 | println!("quiet: {}", quiet); 4 | quiet = true; | ^^^^^^^^^^^^ cannot assign twice to immutable variable | help: consider making this binding mutable | 2 | let mut quiet = false; | +++
What does this print?
892
Reveal the answer
The program prints: 9 push_str adds , café to the end, so the String holds ok, café: eight letters, counting the comma and the space. But len() counts bytes, and the accented é takes two, so the answer is 9. Lesson 2.5 has both halves of this.
What does this print?
about 5 bytes eachabout 5.75 bytes eachabout 6 bytes each
Reveal the answer
The program prints: about 5 bytes each Both numbers are whole numbers, so the answer is a whole number too. 23 divided by 4 is 5 with 3 left over, and the leftover is dropped, not rounded up. To keep the fraction you need decimal numbers such as f64 (lesson 2.3).
Does this compile — and if it does, does it run?
- It compiles and runs
- Compile error E0308
- It compiles, then panics
Reveal the answer
It does not compile: E0308. The type says a pair, (u32, u32), and the value has three parts. A tuple always has exactly as many parts as its type says, so this is a value of the wrong type: E0308, "expected a tuple with 2 elements, found one with 3 elements". Lesson 2.6 covers tuples.
error[E0308]: mismatched types --> src/main.rs:1:29 | 1 | const VERSION: (u32, u32) = (0, 2, 1); | ---------- ^^^^^^^^^ expected a tuple with 2 elements, found one with 3 elements | | | expected because of the type of the constant | = note: expected tuple `(u32, u32)` found tuple `(u32, u32, {integer})`
Does this compile — and if it does, does it run?
- It compiles and runs
- It compiles, then panics
- Compile error E0384
Reveal the answer
It compiles, then panics at run time. It compiles, because mut allows the change. The first subtraction takes unread to 0, the smallest u8; the second asks for minus one, which a u type has no pattern for. The program stops with attempt to subtract with overflow: the edge at the bottom works just like the one at the top (lesson 2.4).
What does this print?
505hello
Reveal the answer
The program prints: 50 Each let makes a brand new name that hides the one before, so no mut is needed. The second is the length of hello, 5 bytes, a number now and not text; the third is that times 10. Shadowing can even change the type, which mut cannot (lesson 2.2).
What does this print?
Sam has sent 4Sam has sent 33 has sent Sam
Reveal the answer
The program prints: Sam has sent 4 Destructuring matches by position: name takes the first part, "Sam", and sent the second, 3. The second hole is filled with sent + 1, which is worked out first, so it prints 4. The tuple itself still holds 3 (lesson 2.6).
What does this print?
true truetrue falsefalse falsefalse true
Reveal the answer
The program prints: true false The first hole asks "at most the limit?", and 200 is, so true. The second asks "not quiet and under the limit?": not quiet is true, but 200 is not less than 200, and one false side makes && false. The difference between < and <= is the whole question (lesson 2.3).
Milestone: a status line
Now the chapter all at once. Chatterbox will one day print a status line after each message: who it is, how many messages it has seen, and whether the last one was within the limit. The settings are already at the top of the file as constants. Write three functions: a counter that can never overflow, a check that a message's length is allowed, and the line itself. Read each function's first line and the comment above it: they are the whole specification, and the hidden tests check the edges, so mind every < and <=.
count_after(0, 3) is 3, and near the top of a u32 it stops at the largest value instead of panicking. fits(200) is true, while fits(0) and fits(201) are false. status(3, "hello") is Chatterbox v0.2 | 3 seen | last: 5/200 bytes | fits: true, built from the constants, not typed out. Replace each todo!().
count_after(0, 3) is 3, and near the top of a u32 it stops at the largest value instead of panicking. fits(200) is true, while fits(0) and fits(201) are false. status(3, "hello") is Chatterbox v0.2 | 3 seen | last: 5/200 bytes | fits: true, built from the constants, not typed out. Replace each todo!().
Hidden tests (8): an_empty_message_does_not_fit count_adds count_sticks_at_the_top one_byte_over_does_not_fit exactly_at_the_limit_fits the_status_counts_bytes the_status_line the_status_of_an_empty_message
This exercise runs real Rust in your browser through the official Rust Playground, so it needs JavaScript.
Where this leaves you
If the quiz went well and the tests are green, you have chapter 2: you can name a value, let it change only when it must, choose a number type by what it holds and how big it can get, tell a view of text from text you own, and put a program's fixed facts at the top of the file. Notice what fits could not do: it can say false, but nothing in Chatterbox can act on that yet. Chapter 3 is where a true or false starts choosing what happens next.
Say it out loud, then reveal
What is the difference between <code>let mut</code> and writing <code>let</code> again with the same name?Reveal
let mut lets one name hold a new value later, of the same type. Writing let again is shadowing: a brand new name that hides the old one, and it may even have a different type.A <code>u8</code> holding 0 has 1 taken away, in a program started with plain <code>cargo run</code>. What happens, and how would you stop at the edge on purpose instead?Reveal
u type has no negative values. To stop at the edge on purpose, use a saturating function such as u8::saturating_sub, the subtracting twin of saturating_add.Why are Chatterbox's name, version and length limit constants, while its message counter is a <code>let mut</code>?Reveal
const every function can see. The counter changes while the program runs, so it is a name made with let mut.What does <code>"héllo".len()</code> give, and why not 5?Reveal
len() counts bytes, and the accented letter takes two bytes.Your Chatterbox so far: v0.2 (after lesson 2.6)
Download this version (zip)Unzip, then cargo run inside the folder.
That is lesson 2.7. Tick it off so the course remembers where you are. That is also the end of chapter 2: a few minutes with the course flashcards now makes it stick, and the chapter’s cheat sheet has every idea on one screen.
Go deeper
Questions people ask
What should I know after the values chapter of a Rust course?
How to name a value with let and allow change with let mut, how shadowing differs from mut, which number type to pick and what happens at its largest value, how a bool comes from a comparison, the difference between String and &str, and when to use a const or a tuple.
Is integer overflow a compile error or a crash in Rust?
Usually neither while you work: if the compiler cannot see the overflow in the code itself, a debug build panics at run time with attempt to add or subtract with overflow. Only an overflow made entirely of numbers written in the code is refused at compile time.
I got some quiz answers wrong. Should I go on to chapter 3?
Read the explanation under each wrong answer and revisit the lesson it names. If the milestone exercise passes its tests, you are ready; chapter 3 uses comparisons, String and constants on every page.
Why does len() not count letters in Rust?
Rust stores text as UTF-8, where a plain English letter takes one byte but an accented letter or an emoji takes more. len() reports the number of bytes, which is what the computer stores; counting letters is a separate, slower job.
