We can't find the internet
Attempting to reconnect
Something went wrong!
Attempting to reconnect
← Ground Rules: Values, Types, Control Flow step 15 of 24
loop, while, for, and break with a value
Count the Collatz steps needed to reach 1.
pub fn collatz_steps(start: u64) -> u32
Repeatedly: if the number is even, halve it; otherwise triple it and add one.
Count how many of those operations it takes to arrive at 1. 1 takes 0 steps,
6 takes 8, and 27 takes 111.
The starter does not compile, and its error is the point of the exercise.
Three loops, and when each is right
loop — repeat until something inside says stop. Use it when the exit
condition is not a simple test at the top, which is exactly this problem.
while cond — test at the top, repeat while true. Use it when there is a
single, cheap condition.
for item in iterable — walk a collection or a range. This is the one you
should reach for by default, and Rust makes it the only pleasant way to walk a
collection, which is not an accident.
loop gets a privilege the other two do not have: because it can only be left
by break (or return, or a panic), the compiler knows it either runs forever
or exits through a break you wrote — so loop can produce a value.
let answer = loop {
if done {
break 42; // this is the loop's value
}
// …
};
break; with nothing after it breaks with (). break value; breaks with
value. Both are legal; they just have different types. The starter breaks with
nothing, so its loop is worth (), so the function — which promised u32 —
gets E0308: mismatched types, expected u32, found ().
while and for cannot do this: they can end by their condition going false,
and there would be no value to produce in that case. Their type is always ().
The gate’s best teaching moment in this track
Write this and clippy stops you:
for i in 0..v.len() {
total += v[i];
}
needless_range_loop is on by default and it will tell you to write
for item in v instead — or v.iter().enumerate() if you genuinely need the
index. Its argument is not aesthetic. The index version does a bounds check on
every access, it lets you index the wrong collection by mistake, and it puts a
number between you and the thing you actually wanted. Iterating directly cannot
be off by one.
Be aware of a real gap in the lint: a hand-rolled while i < v.len() index loop
does not trip it. The lint recognises the for … in 0..len shape, not the
idea. So the gate will not catch every version of this mistake, and you should
learn the habit rather than relying on the tool.
is_multiple_of again
n % 2 == 0 on a u64 trips manual_is_multiple_of (stabilised as a method in
1.87, linted since). Write n.is_multiple_of(2).
A note on the numbers
start is a u64 and the intermediate values genuinely need the room: the
Collatz sequence for 27 climbs to 9232 on its way down. There is no known input
for which this loop does not terminate, and there is also no proof that one does
not exist — the Collatz conjecture is open. The test inputs are all small and
verified.
Loading visualization…
Stuck?
Rust reference solution
Sign in to attempt this problem and reveal the reference solution.