Go for Loop
Go for Loop
Go has exactly one looping keyword: for. Rather than providing separate while, do-while, and for constructs like many other languages, Go's single for statement is flexible enough to express all of them — traditional counting loops, condition-only loops, and infinite loops.
Each time the loop body runs is called an iteration.
Basic Syntax
for initialization; condition; post {
// code executed in each iteration
}
The three components:
- Initialization — runs once, before the loop starts (typically declares a counter variable).
- Condition — checked before every iteration; the loop continues while it's
trueand stops the moment it'sfalse. - Post statement — runs after every iteration (typically increments or updates the counter).
All three components are optional, but the loop must still be logically controlled somehow, or it runs forever.
Example: Printing Numbers
package main
import "fmt"
func main() {
for i := 1; i <= 5; i++ {
fmt.Println("Count:", i)
}
}
Expected output:
Count: 1
Count: 2
Count: 3
Count: 4
Count: 5
Example: Custom Step Size
package main
import "fmt"
func main() {
for i := 0; i <= 50; i += 5 {
fmt.Println(i)
}
}
This increments by 5 each iteration instead of 1.
Other Forms of for
Because all three components are optional, Go's single for keyword covers cases other languages split into separate constructs.
A "while" loop — condition only:
count := 0
for count < 5 {
fmt.Println(count)
count++
}
An infinite loop — no components at all, exited with break:
for {
// runs forever until a break statement is reached
}
This form is common for servers and long-running processes that loop until an external signal tells them to stop.
Using continue
continue skips the rest of the current iteration and jumps straight to the next one, re-checking the condition.
package main
import "fmt"
func main() {
for i := 1; i <= 6; i++ {
if i == 4 {
continue
}
fmt.Println(i)
}
}
Expected output:
1
2
3
5
6
Notice 4 is skipped, but the loop still continues through 5 and 6 — continue does not stop the loop, only the current pass through it.
Using break
break exits the loop immediately, regardless of the loop's condition.
package main
import "fmt"
func main() {
for i := 1; i <= 6; i++ {
if i == 4 {
break
}
fmt.Println(i)
}
}
Expected output:
1
2
3
Once i reaches 4, the loop stops entirely — 5 and 6 are never reached.
Nested Loops
A loop can contain another loop. The inner loop runs to completion for every single iteration of the outer loop.
package main
import "fmt"
func main() {
colors := []string{"Red", "Blue"}
items := []string{"Pen", "Book", "Bag"}
for i := 0; i < len(colors); i++ {
for j := 0; j < len(items); j++ {
fmt.Println(colors[i], items[j])
}
}
}
Note: break and continue inside a nested loop only affect the innermost loop by default. To break out of an outer loop from inside a nested one, label the outer loop and reference that label:
outer:
for i := 0; i < len(colors); i++ {
for j := 0; j < len(items); j++ {
if colors[i] == "Blue" {
break outer // exits both loops immediately
}
fmt.Println(colors[i], items[j])
}
}
The range Keyword
range simplifies iterating over arrays, slices, strings, and maps, automatically producing an index (or key) and a value on each pass.
for index, value := range collection {
// code
}
Example: Iterating with range
package main
import "fmt"
func main() {
languages := []string{"Go", "Python", "Java"}
for index, value := range languages {
fmt.Printf("Index: %d, Value: %s\n", index, value)
}
}
Expected output:
Index: 0, Value: Go
Index: 1, Value: Python
Index: 2, Value: Java
Ignoring the Index or the Value
Use the blank identifier _ to discard whichever part you don't need — Go requires every declared variable to be used, so _ is the idiomatic way to signal "I'm intentionally ignoring this."
Ignore the index:
for _, value := range languages {
fmt.Println(value)
}
Ignore the value:
for index := range languages {
fmt.Println(index)
}
range is covered again in the Arrays, Slices, and Maps lessons, since each of those data structures has its own small variations on how range behaves — for example, ranging over a map yields keys and values but in no guaranteed order, while ranging over a string yields byte positions and Unicode code points rather than plain indices.
Common Mistakes
- Forgetting the post statement (
i++) and accidentally writing an infinite loop. - Modifying the loop variable inside the body in a way that unintentionally changes how many times the loop runs — this works, but is easy to get wrong and usually a sign the logic should be restructured.
- Trying to use
break/continueto affect an outer loop without a label, and being surprised when only the inner loop is affected.