Go For Loops
The for
loop is Go's only looping construct, but don't let that fool you - it's incredibly versatile! Unlike many other programming languages that have separate loop constructs like while
and do-while
, Go simplifies things by providing a single, flexible looping structure that can be adapted to handle all your iteration needs.
Introduction to For Loops
In Go, the for
loop serves as the universal tool for repetitive tasks. Whether you need to iterate a specific number of times, loop while a condition is true, or process items in a collection, the for
loop has you covered.
If you're coming from other programming languages, you'll find Go's approach refreshingly simple - just one loop construct to learn!
Basic For Loop Syntax
Let's start with the most common form of the for
loop, which looks similar to what you might find in C, Java, or JavaScript:
for initialization; condition; post {
// Loop body
}
Where:
- initialization: Executes once before the loop starts
- condition: Checked before each iteration; the loop continues while this is true
- post: Executes at the end of each iteration
Here's a simple example:
package main
import "fmt"
func main() {
for i := 0; i < 5; i++ {
fmt.Println("Iteration:", i)
}
}
Output:
Iteration: 0
Iteration: 1
Iteration: 2
Iteration: 3
Iteration: 4
How It Works:
i := 0
- We initialize a variablei
to 0 (this runs once)i < 5
- Before each iteration, we check ifi
is less than 5- If the condition is true, we execute the loop body
i++
- After each iteration, we incrementi
- Repeat steps 2-4 until the condition becomes false
For as a While Loop
Go doesn't have a dedicated while
loop. Instead, you can use the for
loop with just a condition:
package main
import "fmt"
func main() {
sum := 1
for sum < 100 {
sum += sum
fmt.Println("Current sum:", sum)
}
fmt.Println("Final sum:", sum)
}
Output:
Current sum: 2
Current sum: 4
Current sum: 8
Current sum: 16
Current sum: 32
Current sum: 64
Current sum: 128
Final sum: 128
In this example, we're doubling sum
repeatedly until it exceeds 100. The loop behaves like a while
loop in other languages.
Infinite Loops
You can create an infinite loop by omitting the condition entirely:
for {
// This will run forever unless broken
if someCondition {
break // Exit the loop
}
}
Here's a practical example:
package main
import (
"fmt"
"math/rand"
"time"
)
func main() {
// Seed the random number generator
rand.Seed(time.Now().UnixNano())
counter := 0
for {
// Generate random number between 0 and 9
num := rand.Intn(10)
counter++
fmt.Printf("Attempt %d: Got number %d
", counter, num)
// Exit when we get a 7
if num == 7 {
fmt.Printf("Found 7 after %d attempts!
", counter)
break
}
// Safety valve - don't run more than 20 iterations
if counter >= 20 {
fmt.Println("Giving up after 20 attempts")
break
}
}
}
This will keep generating random numbers until it either finds a 7 or makes 20 attempts.
Always ensure infinite loops have a way to terminate, such as a break
statement, or they'll run forever and potentially crash your program!
For-Range Loop
One of the most powerful variations of the for
loop in Go is the "for-range" loop, which is used to iterate over elements in various data structures:
package main
import "fmt"
func main() {
// Iterating over a slice
fruits := []string{"apple", "banana", "cherry", "dragonfruit"}
fmt.Println("Fruits in my basket:")
for index, fruit := range fruits {
fmt.Printf("%d: %s
", index, fruit)
}
// Iterating over a map
calories := map[string]int{
"apple": 52,
"banana": 96,
"cherry": 50,
"dragonfruit": 60,
}
fmt.Println("
Calorie content:")
for fruit, cal := range calories {
fmt.Printf("%s: %d calories
", fruit, cal)
}
}
Output:
Fruits in my basket:
0: apple
1: banana
2: cherry
3: dragonfruit
Calorie content:
apple: 52 calories
banana: 96 calories
cherry: 50 calories
dragonfruit: 60 calories
The range
form of the for
loop iterates over:
- Arrays or slices
- Strings (by rune)
- Maps
- Channels
What You Get With Range
The values returned by range
depend on the type being iterated:
Type | First Value | Second Value |
---|---|---|
Array/Slice | Index | Value at index |
String | Index | Unicode code point (rune) |
Map | Key | Value |
Channel | Value | - |
Using the Blank Identifier
If you only need one of the values from range, you can use the blank identifier (_
) to ignore the other:
// If you only need the values, not the indices
for _, fruit := range fruits {
fmt.Println("I have a", fruit)
}
// If you only need the indices
for i, _ := range fruits {
fmt.Println("Fruit index:", i)
}
// OR more concisely:
for i := range fruits {
fmt.Println("Fruit index:", i)
}
Control Flow in Loops
Go provides two important statements for controlling the flow within loops:
Break
The break
statement exits the innermost loop immediately:
package main
import "fmt"
func main() {
fmt.Println("Finding the first number divisible by both 3 and 7:")
for i := 1; i <= 100; i++ {
if i%3 == 0 && i%7 == 0 {
fmt.Printf("Found it! %d is divisible by both 3 and 7
", i)
break
}
fmt.Printf("Checked %d
", i)
}
}
This will stop as soon as it finds the first number (21) that's divisible by both 3 and 7.
Continue
The continue
statement skips the rest of the current iteration and jumps to the next iteration:
package main
import "fmt"
func main() {
fmt.Println("Printing only odd numbers:")
for i := 1; i <= 10; i++ {
if i%2 == 0 {
// Skip even numbers
continue
}
fmt.Println(i)
}
}
Output:
Printing only odd numbers:
1
3
5
7
9
Labeled Loops
Go allows you to label loops and use those labels with break
and continue
statements to control outer loops:
package main
import "fmt"
func main() {
fmt.Println("Multiplication table:")
outer:
for i := 1; i <= 5; i++ {
for j := 1; j <= 5; j++ {
if i*j > 15 {
fmt.Println("Stopping at", i, "*", j, "=", i*j)
break outer // Break out of both loops
}
fmt.Printf("%d * %d = %d
", i, j, i*j)
}
}
}
This example will print the multiplication table but stop completely once the product exceeds 15.
Practical Examples
Example 1: File Processing Line by Line
Here's how you might use a loop to process a file line by line:
package main
import (
"bufio"
"fmt"
"os"
"strings"
)
func main() {
// Sample text file content
fileContent := `Hello, World!
This is line 2.
And this is line 3.
#This is a comment
The end.`
// Create a string reader (in a real program, this would be a file)
reader := strings.NewReader(fileContent)
scanner := bufio.NewScanner(reader)
lineNumber := 0
// Scan line by line
for scanner.Scan() {
lineNumber++
line := scanner.Text()
// Skip comment lines
if strings.HasPrefix(line, "#") {
fmt.Printf("Line %d: (skipping comment)
", lineNumber)
continue
}
fmt.Printf("Line %d: %s
", lineNumber, line)
}
if err := scanner.Err(); err != nil {
fmt.Fprintln(os.Stderr, "reading input:", err)
}
}
Output:
Line 1: Hello, World!
Line 2: This is line 2.
Line 3: And this is line 3.
Line 4: (skipping comment)
Line 5: The end.
Example 2: Implementing a Simple Retry Mechanism
package main
import (
"fmt"
"math/rand"
"time"
)
func main() {
rand.Seed(time.Now().UnixNano())
const maxRetries = 5
success := false
for attempt := 1; attempt <= maxRetries; attempt++ {
fmt.Printf("Attempt %d of %d...
", attempt, maxRetries)
// Simulate an operation that might fail
if rand.Float64() < 0.3 { // 30% chance of success
fmt.Println("Success!")
success = true
break
}
fmt.Println("Failed. Retrying...")
// Add exponential backoff between retries
if attempt < maxRetries {
backoff := time.Duration(attempt * attempt * 100) * time.Millisecond
fmt.Printf("Waiting for %v before next attempt
", backoff)
time.Sleep(backoff)
}
}
if !success {
fmt.Println("Operation failed after maximum number of retries")
}
}
This example shows how to implement a retry mechanism with exponential backoff, which is a common pattern in network operations.
Visual Representation
Best Practices
- Keep loops simple - If your loop body is getting too complex, consider extracting some logic into separate functions.
- Avoid modifying loop variables inside the loop body (except in the post statement).
- Be cautious with infinite loops - Always ensure there's a way to exit.
- Prefer range-based loops when iterating over collections.
- Use appropriate variable scoping - Variables declared in the init statement are scoped to the loop.
Common Gotchas
Variable Capturing in Closures
One common issue occurs when using variables from loops in closures:
package main
import "fmt"
func main() {
functions := make([]func(), 3)
// This will not work as expected!
for i := 0; i < 3; i++ {
functions[i] = func() {
fmt.Println(i) // Captures the variable i, not its value
}
}
// All functions will print the same value (3)
for _, f := range functions {
f()
}
fmt.Println("Fixed version:")
// The correct way: create a new variable in each iteration
functions = make([]func(), 3)
for i := 0; i < 3; i++ {
val := i // Create a new variable
functions[i] = func() {
fmt.Println(val)
}
}
for _, f := range functions {
f()
}
}
The fixed version will print 0, 1, 2 as expected.
Summary
In this tutorial, we've explored Go's versatile for
loop in its various forms:
- Basic three-component loops (like C-style for loops)
- Condition-only loops (like while loops)
- Infinite loops with break conditions
- Range-based loops for collections
We've also covered important control flow statements like break
and continue
, as well as more advanced concepts like labeled loops.
Go's simplified approach to loops actually makes your code more readable and maintainable once you get used to it. By mastering the for
loop in its different forms, you'll be well-equipped to handle any iteration needs in your Go programs.
Exercises
- Write a program that prints all even numbers between 1 and 20.
- Create a function that finds the largest number in a slice using a for loop.
- Write a program that counts the frequency of each word in a string.
- Implement a simple "FizzBuzz" program using for loops: Print numbers from 1 to 100, but for multiples of 3 print "Fizz", for multiples of 5 print "Buzz", and for multiples of both print "FizzBuzz".
- Write a nested loop that prints a simple pattern of asterisks in the shape of a right triangle.
Additional Resources
- Go Tour: For loop
- Effective Go: For loops
- Go by Example: For loops
- Go Playground - Try out your loops interactively
If you spot any mistakes on this website, please let me know at [email protected]. I’d greatly appreciate your feedback! :)