A loop runs a block of code repeatedly. Most languages have several loop keywords — for, while, do-while, foreach. Go has just one: for. But that single keyword covers every looping pattern you’ll ever need.

The classic for loop

The full form has three parts separated by semicolons: an init, a condition, and a post:

package main

import "fmt"

func main() {
    for i := 0; i < 5; i++ {
        fmt.Println("i =", i)
    }
}
i = 0
i = 1
i = 2
i = 3
i = 4

What happens, step by step:

  1. Init (i := 0) — runs once, before the loop starts
  2. Condition (i < 5) — checked before each iteration. If false, the loop ends.
  3. Body — runs while the condition is true
  4. Post (i++) — runs after each iteration, before the next condition check

This is the same pattern as for in C, Java, or JavaScript — just without the parentheses.

for as a while loop

Drop the init and post and you’ve got a while loop:

// inside main()
n := 10
for n > 0 {
    fmt.Println(n)
    n--
}
10
9
8
...
1

Go doesn’t have a while keyword — for with just a condition is the equivalent.

Infinite loop

Drop the condition entirely and the loop runs forever — until you explicitly stop it:

// inside main()
count := 0
for {
    count++
    if count == 3 {
        break
    }
    fmt.Println("Iteration", count)
}
fmt.Println("Done")
Iteration 1
Iteration 2
Done

Two new keywords appeared:

  • break — immediately exits the loop
  • continue (which we’ll see in a moment) — skips the rest of the current iteration and goes back to the condition check

break and continue

package main

import "fmt"

func main() {
    for i := 1; i <= 10; i++ {
        if i%2 == 0 {
            continue
        }
        if i > 7 {
            break
        }
        fmt.Println(i)
    }
}
1
3
5
7

Walk through it:

  • i = 1 → odd, less than 7 → print
  • i = 2 → even → continue → skip to next iteration
  • i = 3 → odd, less than 7 → print
  • i = 7 → odd, not greater than 7 → print
  • i = 8 → even → continue → second if never runs
  • i = 9 → odd, but 9 > 7break → loop exits (so i = 10 is never reached)

Subtle, right? That’s why running these examples and changing them is the only way to truly grasp loops.

Looping over a range

Often you don’t care about counter mechanics — you just want to walk through a collection. The range keyword does this:

package main

import "fmt"

func main() {
    fruits := []string{"apple", "banana", "cherry"}

    for index, fruit := range fruits {
        fmt.Println(index, fruit)
    }
}
0 apple
1 banana
2 cherry

range returns two values per iteration — the index and the value. (We’re using a slice here, which we’ll cover properly in the next section. For now, treat []string{...} as “a list of strings”.)

If you only care about the value, ignore the index with _:

// inside main()
for _, fruit := range fruits {
    fmt.Println(fruit)
}

If you only care about the index (rare, but possible):

// inside main()
for index := range fruits {
    fmt.Println(index)
}

The blank identifier _ is Go’s way of saying “I know there’s a value here but I don’t want it.” Use it whenever you need to discard something.

A practical example

Let’s combine everything we’ve learned in this section into one complete program — counting how many even numbers are between 1 and 20:

package main

import "fmt"

func main() {
    evens := 0

    for i := 1; i <= 20; i++ {
        if i%2 != 0 {
            continue
        }
        evens++
    }

    fmt.Println("There are", evens, "even numbers between 1 and 20")
}
There are 10 even numbers between 1 and 20

It uses a for loop, an if with a comparison and modulo, and continue — every concept from this section in 12 lines.

What’s next

You’ve now covered every fundamental piece of Go’s syntax: variables, types, operators, conditionals, and loops. Programs aren’t just made of single values, though — real software works with collections of data. That’s the next section: arrays, slices, maps, pointers, and structs.

Toggle theme (T)