Counting backwards
A for loop doesn't have to count up. If the loop variable starts high, the post statement makes it smaller and the condition keeps it above a lower limit, the loop counts down. Three things change compared with a loop that counts up: the start is the biggest value, the post statement subtracts, and the condition uses > or >= instead of < or <=.
for i := 7; i > 2; i-- {
fmt.Println(i)
}
This prints 7, 6, 5, 4 and 3, one per line. The loop stops when i becomes 2, because 2 > 2 is false. Writing i >= 3 instead gives the same output.
Following the countdown
In the example above, the loop works like this:
i := 7runs once. Is7 > 2? Yes, so 7 is printed, andi--makes it 6.- The check and print repeat for 6, 5, 4 and 3.
- After 3 is printed,
ibecomes 2. Is2 > 2? No, so the loop ends.
Everything else about a downward loop works exactly like an upward one: the condition is checked first, the body runs, then the post statement runs.
Choosing the parts
- Initialization: the first value to print, which is the largest.
- Condition: true for every value you want, false just beyond the last one. Use
>=to include the lower limit and>to exclude it. - Post statement:
i--to go down by 1, or something likei -= 2to go down faster.
Counting down is common when you want to visit things from the end, for example the indices of a slice from len(nums) - 1 down to 0.
Two more examples
A larger step skips values on the way down. This loop prints 10, 7, 4 and 1, then stops because the next value, -2, fails the condition:
for i := 10; i > 0; i -= 3 {
fmt.Println(i)
}
Going through a slice from the end uses the last valid index, len(nums) - 1, as the start. With nums := []int{4, 8, 15}, this prints 2 15, then 1 8, then 0 4:
for i := len(nums) - 1; i >= 0; i-- {
fmt.Println(i, nums[i])
}
Mistakes that are easy to make
- Using
<in the condition.for i := 7; i < 2; i--is false on the first check, so nothing is printed at all. - Counting the wrong way.
for i := 7; i > 2; i++never makes the condition false, so the loop runs forever. The variable moves away from the limit on every pass, so the condition stays true. - Off by one at the end.
i > 0stops before 0 is printed, andi >= 0includes it. - Unsigned counters. With a
uintvariable,i >= 0is always true, becausei--at 0 wraps to the largest value. A loop that counts down to zero should useint, as Go code usually does.
The exercise
The task is to print every number from 5 down to -5, in decreasing order. That is eleven numbers: 5, 4, 3, 2, 1, 0, -1, -2, -3, -4, -5.
Step one is the loop header. Declare i with := at 5. Because -5 itself has to be printed, the condition is i >= -5, not i > -5. The lesson lowers i by 1 after each pass with i += -1, which has the same effect as i--.
Step two is the body, which prints i with fmt.Println. Negative numbers need nothing special, and the loop passes straight through 0.
for i := 5; i >= -5; i += -1 {
fmt.Println(i)
}
Adding a negative number is the same as subtracting, so i += -1, i -= 1 and i-- are interchangeable here.
Key takeaways
- To count down, start high, subtract in the post statement and use
>or>=in the condition. - Choose
>=when the lower limit must be included. - If the loop's direction and condition disagree, the loop either never runs or never ends.
- Counting down to zero with an unsigned type doesn't work; use
int.