Loops in Go

Master Go's only loop keyword, for: the three-component form, while-style and infinite loops, for range over slices and maps, plus break, continue and labels.

Prerequisites

Learning objectives

  • Write the three forms of the for loop and the infinite loop
  • Iterate slices and maps with for range
  • Control a loop with break, continue and labels

Go has exactly one loop keyword: for. There is no while and no do. That one keyword takes a few shapes, which together cover every kind of repetition you need.

The three-component for loop

The classic form has an init statement, a condition, and a post statement, separated by semicolons. The loop runs while the condition is true.

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

i is scoped to the loop, so it disappears once the loop ends.

The while-style loop

Drop the init and post statements and you get a condition-only loop — Go’s equivalent of a while. The semicolons go away too.

n := 1
for n < 100 {
	n *= 2
}

The infinite loop

Drop the condition as well and the loop runs forever. You leave it with break (or return). This form is common for servers and read loops.

for {
	line, ok := next()
	if !ok {
		break
	}
	process(line)
}

Ranging over slices and maps

for range walks a collection. Over a slice it yields the index and a copy of each element:

letters := []string{"a", "b", "c"}
for i, letter := range letters {
	fmt.Println(i, letter)
}

Over a map it yields the key and the value, in an unspecified order that can change between runs:

stock := map[string]int{"pens": 4, "books": 7}
for name, qty := range stock {
	fmt.Printf("%s: %d\n", name, qty)
}

break and continue

break stops the loop immediately; continue skips to the next iteration.

for i := 1; i <= 10; i++ {
	if i%2 != 0 {
		continue // skip odd numbers
	}
	if i > 6 {
		break // stop once we pass 6
	}
	fmt.Println(i)
}

Labels for nested loops

A break or continue normally affects the innermost loop. To target an outer loop, attach a label to it:

outer:
for i := 0; i < 3; i++ {
	for j := 0; j < 3; j++ {
		if i+j == 3 {
			break outer
		}
	}
}

Use labels sparingly — they are handy for grid searches but easy to overuse.

A complete example

This program iterates a slice of temperatures, computes their average and finds the peak. It compiles and runs as-is.

package main

import "fmt"

func main() {
	temperatures := []float64{18.5, 21.0, 19.5, 24.0, 20.0}

	var sum float64
	max := temperatures[0]

	for i, t := range temperatures {
		sum += t
		if t > max {
			max = t
		}
		fmt.Printf("day %d: %.1f°C\n", i+1, t)
	}

	average := sum / float64(len(temperatures))
	fmt.Printf("average: %.1f°C, peak: %.1f°C\n", average, max)
}

Running it prints:

day 1: 18.5°C
day 2: 21.0°C
day 3: 19.5°C
day 4: 24.0°C
day 5: 20.0°C
average: 20.6°C, peak: 24.0°C

Common mistakes

  • Forgetting that the range value is a copy. Assigning to t inside for i, t := range s does not change the slice. Write to s[i] instead.
  • Relying on map order. Ranging a map gives no stable order; sort the keys first if you need determinism.
  • Writing an infinite loop with no exit. A for {} without a reachable break or return hangs the program.

Practice

Print the multiplication table for 7, from 7 x 1 up to 7 x 10, one line per row, like 7 x 3 = 21.

Show the solution
package main

import "fmt"

func main() {
	const n = 7
	for i := 1; i <= 10; i++ {
		fmt.Printf("%d x %d = %d\n", n, i, n*i)
	}
}

A single three-component for loop counts from 1 to 10 and prints one product per iteration.

Summary

  • for is Go’s only loop; it covers counted, while-style and infinite forms.
  • for range iterates slices (index, value) and maps (key, value, no order).
  • break, continue and labels give you precise control over the flow.

Next, package repeated logic into functions, and learn about the collections you loop over in arrays and slices.

Your progress is stored only in this browser. No account is required.

Search

Search runs entirely in your browser.