Loops in Go

By Syncfusion®, Inc. · Last updated

Repeat work in Go with the for loop in its three forms, walk through arrays, slices, strings, maps and channels with range, and control loops with break, continue, labels and goto.

What Are Loops?

Loop = code that repeats while a condition is true.

Iteration = one trip through the loop.

Without a loop, printing roll numbers 1 to 40 needs 40 lines. With a loop, it needs 3.

Simple lesson: a loop repeats work so you do not have to write the same line again and again.

A Real-World Example

At morning assembly, the teacher takes attendance.

  • She starts at roll number 1.
  • She calls one name and marks it.
  • She moves to the next roll number.
  • She stops after the last student.

That is a loop:

  • Start at 1.
  • Check if there are students left.
  • Do the work: call the name.
  • Move to the next number.

Go has only one loop keyword: for.

  • It can count, like a for loop in other languages.
  • It can wait for a condition, like a while loop.
  • It can run forever.
  • With range, it can walk through lists, text, maps and channels.

What You Will Learn

In this lesson, you will learn:

  1. Why loops are used.
  2. The three forms of for: counting, condition-only and infinite.
  3. How range walks through arrays, slices, strings, maps and channels.
  4. How to stop or skip with break and continue, and how labels work.
  5. How to put one loop inside another.

Loop Fundamentals

Why Loops Are Used

  • Repeat a task a fixed number of times, like printing a table.
  • Go through every item in a list, like all students' marks.
  • Keep trying until something happens, like a correct password.
  • Add things up, like a total or a count.

Without and with a loop

package main

import "fmt"

func main() {
	fmt.Println("Roll 1")
	fmt.Println("Roll 2")
	fmt.Println("Roll 3")

	for roll := 1; roll <= 3; roll++ {
		fmt.Println("Roll", roll)
	}
}
Roll 1
Roll 2
Roll 3
Roll 1
Roll 2
Roll 3
  • Both halves print the same thing.
  • Change 3 to 40 in the loop, and it prints 40 lines. The first half would need 37 more lines.

Simple lesson: use a loop when the same work repeats.

The for Loop

Traditional for Loop

for init; condition; post {
	// body
}
  • init runs once, before the first trip.
  • condition is checked before every trip. The loop stops when it is false.
  • post runs after every trip, usually i++.
  • body is the work to repeat.

Move the slider, then step through the loop.

Watch the order:

  • init happens once.
  • Then it is always check, body, post, again and again.
  • The last check is false, and the loop ends.

The 7 times table

package main

import "fmt"

func main() {
	for i := 1; i <= 5; i++ {
		fmt.Println("7 x", i, "=", 7*i)
	}
}
7 x 1 = 7
7 x 2 = 14
7 x 3 = 21
7 x 4 = 28
7 x 5 = 35
  • i lives only inside the loop.
  • You can count down too: for i := 10; i >= 1; i--.

Condition-Only Loop

Leave out init and post. Only the condition stays.

This is Go's version of a while loop.

Save money until you can buy the book

  • Use this form when you do not know how many trips you need.
  • Something inside the loop must change the condition, or it never stops.

Infinite Loop

Infinite loop = for { }, a loop with no condition. It runs until something stops it.

An infinite loop with a way out

package main

import "fmt"

func main() {
	guesses := []int{3, 8, 7}
	secret := 7
	tries := 0
	for {
		guess := guesses[tries]
		tries++
		if guess == secret {
			fmt.Println("Found it in", tries, "tries")
			break
		}
		fmt.Println(guess, "is wrong")
	}
}
3 is wrong
8 is wrong
Found it in 3 tries
  • break jumps out of the loop.
  • Servers often run an infinite loop, waiting for requests.
  • []int{3, 8, 7} is a list of numbers called a slice. You will learn it in Slices.

A loop whose condition never becomes false runs forever.

In this lab, a program that runs too long is stopped after a few seconds. On your computer, press Ctrl + C in the terminal to stop it.

Simple lesson: for can count (init; condition; post), wait (condition only) or run forever (for { }).

The range Loop

range = walk through every item in a collection, one at a time.

Each trip gives you the index (position) and the value.

What range gives you

range with Arrays

range over an array

package main

import "fmt"

func main() {
	days := [3]string{"Mon", "Tue", "Wed"}
	for i, day := range days {
		fmt.Println(i, day)
	}
}
0 Mon
1 Tue
2 Wed
  • Positions start at 0, not 1.
  • You will learn arrays in Arrays.

range with Slices

Total and average of marks

package main

import "fmt"

func main() {
	marks := []int{91, 78, 85, 66}
	total := 0
	for _, m := range marks {
		total += m
	}
	fmt.Println("Total:", total)
	fmt.Println("Average:", float64(total)/float64(len(marks)))
}
Total: 320
Average: 80
  • _ throws away the index, because we only need the marks.
  • Write for i := range marks if you need only the index.

range with Strings

range over a string

package main

import "fmt"

func main() {
	for i, r := range "Hi!" {
		fmt.Println(i, string(r))
	}
}
0 H
1 i
2 !
  • Each r is a rune: one character.
  • For Hindi or emoji, i jumps by more than 1, because those characters use several bytes. See Strings.

range with Maps

Map = a set of key and value pairs, like a phone book. You will learn it in Maps.

Add up a map's values

package main

import "fmt"

func main() {
	books := map[string]int{"Asha": 3, "Ravi": 5, "Meena": 2}
	total := 0
	for _, count := range books {
		total += count
	}
	fmt.Println("Books borrowed:", total)
}
Books borrowed: 10
  • Go walks through a map in a different order each time.
  • So do not rely on the order when you print a map in a loop.
  • Adding up gives the same answer in any order.

range with Channels

Channel = a pipe that one part of a program uses to send values to another. You will learn it in Channels.

range over a channel

package main

import "fmt"

func main() {
	queue := make(chan string, 3)
	queue <- "Asha"
	queue <- "Ravi"
	close(queue)
	for name := range queue {
		fmt.Println("Next:", name)
	}
}
Next: Asha
Next: Ravi
  • range over a channel takes values until the channel is closed.

Simple lesson: range walks through each item and gives you its position and value.

Loop Control Statements

break

break = leave the loop right now.

Stop at the first failing mark

package main

import "fmt"

func main() {
	marks := []int{78, 92, 31, 88}
	for i, m := range marks {
		if m < 35 {
			fmt.Println("First fail at position", i)
			break
		}
		fmt.Println("OK:", m)
	}
}
OK: 78
OK: 92
First fail at position 2

continue

continue = skip the rest of this trip and start the next one.

Print only the even roll numbers

package main

import "fmt"

func main() {
	for roll := 1; roll <= 6; roll++ {
		if roll%2 != 0 {
			continue
		}
		fmt.Println("Roll", roll)
	}
}
Roll 2
Roll 4
Roll 6
  • For odd numbers, continue skips the print.
  • The post statement roll++ still runs.

Labels

Label = a name for a loop, so break or continue can reach an outer loop.

break out of two loops at once

package main

import "fmt"

func main() {
	classes := [][]string{{"Asha", "Ravi"}, {"Meena", "Kabir"}}
	target := "Meena"
search:
	for c, class := range classes {
		for _, name := range class {
			if name == target {
				fmt.Println("Found", name, "in class", c)
				break search
			}
		}
	}
	fmt.Println("Search done")
}
Found Meena in class 1
Search done
  • search: names the outer loop.
  • A plain break would leave only the inner loop.
  • break search leaves both.

goto

goto = jump to a label somewhere else in the same function.

goto (rarely used)

package main

import "fmt"

func main() {
	n := 1
again:
	fmt.Println("Try", n)
	n++
	if n <= 3 {
		goto again
	}
}
Try 1
Try 2
Try 3
  • goto exists, but it makes code hard to follow.
  • Almost always, a for loop is clearer. Prefer it.

Easy way to remember

  • break = leave the loop.
  • continue = skip to the next trip.
  • break label = leave an outer loop.
  • goto = avoid it.

Simple lesson: break stops the loop, continue skips one trip, and labels let you reach an outer loop.

Nested Loops

Nested loop = a loop inside another loop.

For every trip of the outer loop, the inner loop runs all its trips.

A small multiplication grid

Practical Examples

A star triangle

package main

import "fmt"

func main() {
	for row := 1; row <= 4; row++ {
		for star := 1; star <= row; star++ {
			fmt.Print("*")
		}
		fmt.Println()
	}
}
*
**
***
****
  • Row 1 prints 1 star, row 2 prints 2 stars, and so on.
  • The inner loop uses the outer loop's row as its limit.

Class toppers

package main

import "fmt"

func main() {
	names := []string{"8A", "8B"}
	marks := [][]int{{78, 95, 88}, {91, 67, 84}}
	for c, list := range marks {
		best := 0
		for _, m := range list {
			if m > best {
				best = m
			}
		}
		fmt.Println(names[c], "top mark:", best)
	}
}
8A top mark: 95
8B top mark: 91
  • The outer loop picks a class.
  • The inner loop finds the biggest mark in that class.

Simple lesson: in a nested loop, the inner loop finishes all its trips for each trip of the outer loop.

TL;DR

  1. Loop = repeat code. Go has only for.
  2. Traditional = for i := 0; i < n; i++ { }

    • init once, then check, body, post.
  3. Condition-only = for x < 100 { }. Go's "while".
  4. Infinite = for { }. Leave with break.
  5. range = for i, v := range collection { }

    • arrays, slices, strings (runes), maps (random order), channels, integers.
  6. break = leave. continue = next trip. label = reach an outer loop. goto = avoid.
  7. Nested loop = the inner loop runs fully for each outer trip.

Common mistakes

MistakeWrong ideaCorrect ideaWhat goes wrong
for (i := 0; i < 5; i++)Parentheses are neededNo parentheses in GoA syntax error.
while x < 5 { }Go has whileUse for x < 5 { }undefined: while
Forgetting to change the conditionThe loop stops by itselfSomething must change itThe loop never ends.
i <= len(list)The last index is lenThe last index is len - 1index out of range panic.
Printing a map in a loop and expecting orderMaps keep insertion orderMap order changes each runOutput order changes.
break in a nested loop to stop bothbreak leaves all loopsIt leaves only the inner loopThe outer loop keeps going.
for i, v := range marks with i unusedUnused loop variables are fineUse _ for the indexdeclared and not used: i

Check Yourself

Exercises

What to Remember

  • Go has one loop keyword: for.
  • for i := 0; i < n; i++ counts. for cond waits. for { } runs forever.
  • range gives the position and the value of each item.
  • Map order changes every run.
  • break leaves, continue skips, labels reach outer loops. Avoid goto.
  • The inner loop runs fully for every trip of the outer loop.

Next: Functions. You will learn how to name a group of steps and reuse it with different values.