The for loop in Go is the only repetitive structure in the language. With it, we create classic loops, while-style loops, and iterations over collections.
If you come from C, Java, or JavaScript, you’re used to having an arsenal of loops: for, while, do-while, foreach… Sometimes you use one, sometimes another, and sometimes you argue with your team about which is more efficient.
In Go, the designers cut to the chase. Only the for loop exists.
Nothing else is needed. The for loop can behave like traditional loops simply by omitting parts of its syntax.
Equivalents to Other Loops
All the common forms are expressed with for:
| Traditional Loop Type | In Go it’s written… | Syntax |
|---|---|---|
for (i=0; i<10; i++) | classic for | for i:=0; i<10; i++ |
while (condition) | conditional for | for condition |
while (true) | infinite for | for |
do-while | Does not exist | Simulated with an infinite for + if break at the end |
The Classic for Loop
This is the form we all know, identical to C or Java, but without parentheses (just like if).
Syntax: for initialization; condition; post { ... }
package main
import "fmt"
func main() {
// Print from 0 to 4
for i := 0; i < 5; i++ {
fmt.Println("Counter:", i)
}
}Notice that the variable i is declared with := inside the loop itself. This means i only exists inside the loop. If you try to access it outside, you’ll get an error.
The for as while
In other languages, we use while when we don’t know how many iterations we’ll perform, but rather depend on a boolean condition.
In Go, to achieve this, we simply omit the initialization and post parts. We leave only the condition.
func main() {
counter := 1
// This is equivalent to: while (counter < 100)
for counter < 100 {
counter *= 2
fmt.Println("The counter is now:", counter)
}
}There’s no need for a new keyword: if we only write a condition, it behaves like a while.
The Infinite Loop
What if we want a loop that never ends (or until we manually stop it)? This is the typical case of a web server listening for requests or a game in its game loop.
In Go, we omit everything.
func main() {
for {
fmt.Println("This never stops!")
// We'll need a mechanism to exit, or Ctrl+C
}
}This is the canonical way to do a while(true) in Go.
Loop Control with break and continue
As in other languages, we have two keywords to alter the normal flow inside a loop:
- break: Breaks the loop immediately and exits it.
- continue: Skips the current iteration and jumps directly to the next one (executing the “post” step if it’s a classic
for).
Example with break
We are looking for a number and want to stop as soon as we find it.
for i := 0; i < 10; i++ {
if i == 5 {
fmt.Println("Found 5! We're leaving.")
break // Exits the for loop immediately
}
fmt.Println("Searching...", i)
}Example with continue
We want to print only the odd numbers.
for i := 0; i < 5; i++ {
if i%2 == 0 {
continue // It's even, skip this iteration
}
fmt.Println("Odd:", i)
}Labels in Nested Loops
This is something you don’t see every day, but it’s very useful when working with complex algorithms. If you have a loop inside another loop and want to do a break that exits both, you can use labels.
func main() {
// Define a label called "OuterLoop"
OuterLoop:
for i := 0; i < 3; i++ {
for j := 0; j < 3; j++ {
fmt.Println(i, j)
if i == 1 && j == 1 {
fmt.Println("Breaking everything!")
break OuterLoop // Breaks the labeled outer loop
}
}
}
fmt.Println("End of program")
}Without the label, the break would only exit the inner loop (j), and the outer loop (i) would continue executing.
Iteration over Collections
Although we will dedicate a full article to collections, it’s impossible to talk about for without briefly mentioning the range clause. It’s the equivalent of the foreach in C# or for..of in JS.
names := []string{"Luis", "Juan", "Ana"}
for index, value := range names {
fmt.Printf("Position %d: %s\n", index, value)
}We’ll look at this in depth when we talk about arrays and slices.