What an infinite loop is
A loop is infinite when its condition never becomes false. The program keeps repeating the body and never reaches the code after the loop. In Go, an infinite loop is sometimes what you want, and sometimes a bug.
On purpose
A for with no condition runs until something inside the body stops it, usually a break or a return:
k := 0
for {
k++
if k == 3 {
break
}
}
Servers and programs that wait for input are built this way. After the loop, k is 3.
By accident
With a three-part header, an accidental infinite loop usually comes from the loop variable and the condition not agreeing:
- the post statement moves the variable the wrong way, away from the value that would end the loop;
- the body changes the variable and undoes the post statement, so it never advances;
- the condition tests for an exact value with
!=, and the variable jumps over that value.
The loop in the lesson's statement is the second kind. Each pass prints i, runs i-- in the body, and then i++ in the header cancels it. The value is 0 at the start of every pass, so i < 10 is always true and the program prints 0 forever.
The exercise: counting down from 15
The program should print the odd numbers from 15 down to 1: 15, 13, 11 and so on. Instead it prints 15, 16, 17 and keeps going. The starting code is:
for number := 15; number != 0; number++ {
fmt.Println(number)
}
Three things are wrong, and each one matches a cause above.
- The direction. The post statement is
number++, so the value grows while the loop is supposed to end at a small value. It moves away from the stop value on every pass. - The step. To visit 15, 13, 11 and so on, the loop must subtract 2, not 1. The post statement becomes
number -= 2. - The condition. After subtracting 2 repeatedly, the sequence is 15, 13, ..., 3, 1, -1, and it never equals 0, because every value is odd. So
number != 0is never false. Replacing it withnumber > 0lets the loop stop at the first value that is zero or below, which is -1.
The fixed loop:
for number := 15; number > 0; number -= 2 {
fmt.Println(number)
}
It prints 15, 13, 11, 9, 7, 5, 3 and 1. After 1 is printed, number becomes -1, -1 > 0 is false and the loop ends.
How to avoid infinite loops
- Prefer a range check to an exact one. Conditions with
<,<=,>or>=still end when a step jumps past the limit.!=only works if the variable lands exactly on the value. - Check the direction. Counting down needs a subtracting post statement and a
>-style condition. Counting up needs the opposite. - Don't change the loop variable in the body unless you have a reason. Updating it in two places makes the loop hard to follow.
- Trace the first three passes by hand and ask what the variable is at the start of each one.
When a program in the editor seems stuck, an infinite loop is a likely cause, and a loop that prints without stopping is easy to spot.
Key takeaways
- A loop runs forever when its condition never becomes false.
for { }is Go's deliberate infinite loop; usebreakorreturnto leave it.- The usual accidental causes are the wrong direction, a body that undoes the post statement, and an exact
!=test that gets skipped. - With a step larger than 1, use a range condition such as
> 0instead of!= 0.