18. Loops

The other way out of repeating yourself is the loop: a block of code that runs over and over. Chapters 03 and 04 showed that Go has one loop keyword, for, and no other. for comes in several forms, plus break for stopping early and continue for skipping a round. All are covered here.

for with a condition: repeat as long as it is true

The most general form has just a condition. Go checks it, runs the block if it is true, then checks again, repeating until it is false.

count := 10
for count > 0 {
    fmt.Println(count)
    count = count - 1
}
fmt.Println("Blast off!")

Run order:

  1. Check count > 0. It is 10, so true.
  2. Print 10, set count to 9.
  3. Back to step 1. count is 9, still true. Print, subtract one.
  4. Repeat until count is 0. The condition fails, the loop exits, and fmt.Println("Blast off!") runs once.

The rules from if apply: no parentheses, and the { stays on the same line. This is exercises/18/02-countdown.go.

Inside the body, change a value the condition depends on, or the loop never ends. An infinite loop locks the terminal. Stop it with Ctrl + C.

Shorter ways to change a variable

Loops change variables all the time, so Go has short forms. i++ adds 1 to i, which you have seen since Chapter 04. i-- subtracts 1. +=, -=, and *= apply an operation to the variable itself, so total += 5 means total = total + 5. += joins strings too:

score := 10
score++
fmt.Println(score) // 11
score--
score--
fmt.Println(score) // 9
score += 5
fmt.Println(score) // 14
score -= 4
fmt.Println(score) // 10
score *= 3
fmt.Println(score) // 30

line := "ab"
line += "c"
fmt.Println(line) // abc

score++ is a statement on its own line. It does not give a value, so you cannot write it inside fmt.Println.

The three-part for: repeat a known number of times

This is the right form when you know how many times to repeat. You met it in Chapter 04:

for i := 1; i <= 5; i++ {
    fmt.Println(i)
}

Output:

1
2
3
4
5

The three parts are separated by semicolons:

  • i := 1 runs once, before the first round.
  • i <= 5 is the condition, checked before each round.
  • i++ runs after each round.

Watch the end value. i <= 5 includes 5, and i < 5 stops at 4. Getting this wrong by one is the most common bug in loops, so read the condition carefully. To loop from 1 to 10, write i <= 10.

A variable declared in the first part exists only inside the loop. Using it afterwards stops with:

for i := 1; i <= 3; i++ {
    fmt.Println(i)
}
fmt.Println(i)
undefined: i

If you need the counter after the loop, declare it before the loop, as the condition form does.

A step

The third part sets how the counter changes each round. Change it to skip or to count backwards:

for i := 0; i <= 100; i += 10 {
    fmt.Print(i, " ")
}
fmt.Println()

for i := 10; i > 0; i-- {
    fmt.Print(i, " ")
}
fmt.Println()

Output:

0 10 20 30 40 50 60 70 80 90 100
10 9 8 7 6 5 4 3 2 1

The direction has to match the condition. for i := 10; i > 0; i++ starts above zero and keeps going up, and i += 0 never changes i at all. Go accepts both, and the loop does not end when you meant it to.

fmt.Print(i, " ") prints a value and a space, with no new line. The plain fmt.Println() at the end moves to a new line. These examples are in exercises/18/04-step.go.

Open exercises/18/01-for-table.go. It prints the multiplication table of 7, from 7 * 1 to 7 * 10. Change it to print the table of any other number.

The bare for with break

Any loop can be cut short with break, which jumps straight to whatever comes after the loop. A for with nothing after it has no built-in exit, and the only way out is break:

n := 1
for {
    if n*n > 100 {
        break
    }
    n++
}
fmt.Println("First number whose square is over 100 is", n)

Output:

First number whose square is over 100 is 11

Use the bare for when the exit test does not fit in a single condition at the top. This is exercises/18/05-break.go.

Inside a switch, break leaves the switch, not the loop around it:

for i := 1; i <= 3; i++ {
    switch i {
    case 2:
        fmt.Println("break here")
        break
    }
    fmt.Println("after the switch, i is", i)
}

Output:

after the switch, i is 1
break here
after the switch, i is 2
after the switch, i is 3

The loop carried on. When a loop has to end from inside a decision, use an if chain for that decision.

Running at least once

Sometimes the body must run at least once before the check. Use a bare for with break at the end:

count := 1
for {
    fmt.Println(count)
    count++
    if count > 5 {
        break
    }
}

Output:

1
2
3
4
5

The break at the bottom exits as soon as the condition is met. This is the shape for asking the user something: you have to ask once before you can check the answer. This is exercises/18/03-at-least-once.go.

continue: skip to the next round

Where break exits the loop entirely, continue skips the rest of the current round and goes straight to the next one:

for i := 1; i <= 10; i++ {
    if i%2 == 0 {
        continue // skip even numbers
    }
    fmt.Println(i)
}

Output:

1
3
5
7
9

In a three-part for, the i++ still runs after continue. In a condition form, make sure the variable has already changed before continue, or the loop never ends. The same result can always be written without continue, but it can make the intent clearer. This is exercises/18/06-continue.go.

range over a number

When you only want "do this N times", range is shorter. It counts from 0 up to, but not including, the number:

for i := range 3 {
    fmt.Println("Round", i)
}

for range 2 {
    fmt.Println("Push-up")
}

Output:

Round 0
Round 1
Round 2
Push-up
Push-up

The second form leaves out the variable, for when you do not need the count. This form needs Go 1.22 or newer, which the setup in Chapter 06 gives you. This is exercises/18/07-range-number.go. Chapter 22 uses range to walk through a slice. The rest of this part uses the three-part form, because it can start anywhere and take any step.

Homework

Homework starters are in exercises/18/homework/. Each one runs as it is and prints a placeholder line.

Problem 1 — Count to 20

Open exercises/18/homework/01-count-to-20.go. Use a for with only a condition to print 1 to 20, each on its own line.

Problem 2 — Multiplication table of 7

Open exercises/18/homework/02-mult-table-7.go. Use a three-part for to print the multiplication table of 7, from 7 * 1 to 7 * 12, in this shape:

7 * 1 = 7
7 * 2 = 14
...
7 * 12 = 84

Problem 3 — Stop at the threshold

Open exercises/18/homework/03-stop-at-threshold.go. Loop from 1, adding each number to a running total. Stop once the total exceeds 100, then print the total and the counter value at that moment.

Challenge — Sum 1..N

Open exercises/18/homework/04-sum-1-to-n.go. Prompt for a positive whole number n. Compute 1 + 2 + 3 + ... + n with a for loop and a running total. Print:

Sum from 1 to N is S

Then print the formula n * (n + 1) / 2 on the next line, which gives the same answer without a loop. The two should agree.

Stuck or finished? Open the homework solutions page.