Changing the step and the direction
A counter does not have to go up by 1. The update statement decides how the counter moves, and the condition has to agree with that direction. This lesson looks at two variations: a bigger step, and counting down.
A step of 2
To print the even numbers from 4 through 14, start at 4, go up by 2, and stop after 14:
let mut i = 4;
while i <= 14 {
println!("{}", i);
i += 2;
}
This prints 4, 6, 8, 10, 12 and 14 on separate lines. Because the start is even and the step is 2, every value stays even. The last value, 14, passes the test 14 <= 14, and the next one, 16, fails it.
Counting down
To loop in reverse, start at the large end, subtract in the update, and flip the comparison so that the loop continues while the counter is still at or above the lowest value:
let mut i = 12;
while i >= 4 {
println!("{}", i);
i -= 2;
}
The output is 12, 10, 8, 6, 4. After printing 4, i becomes 2, and 2 >= 4 is false, so the loop ends.
The rule is the same in both directions: the condition must be true for every value you want to print and false for the first value after the last one.
Keeping the parity
The first value and the step together decide which numbers show up. Starting from an even number and stepping by 2 gives only even numbers. Starting from an odd number and stepping by 2 gives only odd numbers. To print odd numbers, you do not need an if inside the loop: starting from an odd value is enough.
The exercise, step by step
The lesson asks you to print all the odd numbers from 23 down to 7, in decreasing order.
- Declare the counter with
let mut counter = 23;. It starts at the top of the range, and 23 is odd. It must bemutbecause the loop will decrease it. - Write the loop condition
counter >= 7. The loop runs while the counter is still at or above 7, so 7 itself is printed. - Print the counter with
println!("{}", counter);. The{}placeholder is replaced by the value. - Subtract 2 with
counter -= 2;. Going from an odd number to the previous odd number takes a step of 2, so the sequence is 23, 21, 19, and so on down to 9 and 7.
let mut counter = 23;
while counter >= 7 {
println!("{}", counter);
counter -= 2;
}
After printing 7, the counter becomes 5, the test 5 >= 7 fails, and the loop stops. Nine numbers are printed: 23, 21, 19, 17, 15, 13, 11, 9 and 7.
Types and counting down
In these examples Rust picks i32 for the counter, which can go below zero without a problem. If you declare a counter as an unsigned type such as u32, be careful when counting down toward zero. A condition like counter >= 0 is always true for an unsigned number, so the compiler warns that the comparison is useless, and subtracting past 0 does not give -1. In a build with optimizations, as the lessons use, it wraps around to a huge number. In a debug build it panics with an overflow error instead. For a countdown by 1 that should stop at 0, a condition like counter > 0 is safe. With a bigger step, an unsigned counter can wrap past the end, so use a signed type there.
Common mistakes
- Using
<=when counting down. Withcounter <= 7starting at 23, the test is false at once and nothing is printed. - Using
+=when counting down, so the counter moves away from the limit and the loop never ends. - Stepping by 1 instead of 2, which prints every number rather than every other one.
- Stopping one value early or late by using
>instead of>=. Withcounter > 7, the last printed number is 9.
Key takeaways
- The update statement sets the step and the direction:
+= 2counts up by twos,-= 2counts down by twos. - When counting down, start high, use
>=(or>) in the condition, and subtract in the update. - The starting value and the step decide which numbers appear, so starting at an odd number and stepping by 2 prints only odd numbers.
- With unsigned types, a countdown past 0 does not go negative.
