Go Loops
Introduction
Loops are fundamental structures in programming that allow you to execute a block of code repeatedly. In Go, loops are essential for tasks like processing collections of data, implementing algorithms, or simply repeating actions a specific number of times.
Unlike many other programming languages that provide various looping constructs (while, do-while, for, foreach), Go simplifies this by providing only the for
loop. However, don't let this fool you—Go's for
loop is versatile and can be configured to behave like all the loop types you might be familiar with from other languages.
In this tutorial, we'll explore the different ways to use loops in Go and how they can help you write efficient, clear code.
Basic For Loop
The most common loop structure in Go is the traditional for
loop with three components:
- Initialization: Executes before the loop starts
- Condition: Evaluated before each iteration
- Post statement: Executes after each iteration
Syntax
for initialization; condition; post {
// Code to be executed
}
Example: Counting from 1 to 5
package main
import "fmt"
func main() {
for i := 1; i <= 5; i++ {
fmt.Println(i)
}
}
Output:
1
2
3
4
5
In this example:
i := 1
initializes a variablei
with value 1i <= 5
is the condition that keeps the loop running as long as it evaluates to truei++
incrementsi
after each iteration
While-style Loops in Go
Go doesn't have a separate while
keyword, but you can create while-style loops using the for
loop with just a condition.
Syntax
for condition {
// Code to be executed
}
Example: Decreasing Counter
package main
import "fmt"
func main() {
count := 5
for count > 0 {
fmt.Println(count)
count--
}
fmt.Println("Liftoff!")
}
Output:
5
4
3
2
1
Liftoff!
In this example, the loop continues as long as count
is greater than 0.
Infinite Loops
You can create an infinite loop by omitting the condition. Make sure to include a break
statement inside to exit the loop when needed.
Syntax
for {
// Code to be executed
if someCondition {
break
}
}
Example: User Input Validation
package main
import "fmt"
func main() {
sum := 0
for {
fmt.Println("Current sum:", sum)
fmt.Println("Enter a number to add (or 0 to exit):")
var input int
fmt.Scan(&input)
if input == 0 {
break
}
sum += input
}
fmt.Println("Final sum:", sum)
}
Sample Interaction:
Current sum: 0
Enter a number to add (or 0 to exit):
5
Current sum: 5
Enter a number to add (or 0 to exit):
10
Current sum: 15
Enter a number to add (or 0 to exit):
0
Final sum: 15
For-each Loops with Range
The range
keyword is used in combination with for
to iterate over elements in various data structures such as arrays, slices, maps, and strings.
Syntax for Slices and Arrays
for index, value := range collection {
// Code to be executed
}
Example: Iterating Over a Slice
package main
import "fmt"
func main() {
fruits := []string{"apple", "banana", "cherry", "durian", "elderberry"}
for i, fruit := range fruits {
fmt.Printf("Index %d: %s
", i, fruit)
}
}
Output:
Index 0: apple
Index 1: banana
Index 2: cherry
Index 3: durian
Index 4: elderberry
If you only need the index or value, you can use:
// Only index
for i := range collection {
// Use i
}
// Only value
for _, value := range collection {
// Use value
}
Example: Iterating Over a Map
package main
import "fmt"
func main() {
capitalCities := map[string]string{
"USA": "Washington, D.C.",
"France": "Paris",
"Japan": "Tokyo",
"India": "New Delhi",
"Brazil": "Brasília",
}
for country, capital := range capitalCities {
fmt.Printf("The capital of %s is %s
", country, capital)
}
}
Output:
The capital of USA is Washington, D.C.
The capital of France is Paris
The capital of Japan is Tokyo
The capital of India is New Delhi
The capital of Brazil is Brasília
Note: The iteration order over maps is not guaranteed in Go.
Control Statements in Loops
Go provides two important control statements for loops:
- break: Exits the loop immediately
- continue: Skips the current iteration and moves to the next one
Example: Using break and continue
package main
import "fmt"
func main() {
for i := 1; i <= 10; i++ {
// Skip even numbers
if i%2 == 0 {
continue
}
// Stop when we reach 7
if i > 7 {
break
}
fmt.Println(i)
}
}
Output:
1
3
5
7
Nested Loops
You can place one loop inside another to create nested loops. This is useful for working with multi-dimensional data structures or when you need to combine elements from different collections.
Example: Multiplication Table
package main
import "fmt"
func main() {
for i := 1; i <= 5; i++ {
for j := 1; j <= 5; j++ {
fmt.Printf("%d×%d=%d\t", i, j, i*j)
}
fmt.Println() // New line after each row
}
}
Output:
1×1=1 1×2=2 1×3=3 1×4=4 1×5=5
2×1=2 2×2=4 2×3=6 2×4=8 2×5=10
3×1=3 3×2=6 3×3=9 3×4=12 3×5=15
4×1=4 4×2=8 4×3=12 4×4=16 4×5=20
5×1=5 5×2=10 5×3=15 5×4=20 5×5=25
Labeled Break and Continue
In nested loops, you might want to break or continue a specific outer loop. Go supports labeled statements to accomplish this.
Example: Finding a Value in a 2D Grid
package main
import "fmt"
func main() {
// Define a 2D grid
grid := [][]int{
{1, 2, 3},
{4, 5, 6},
{7, 8, 9},
}
// Value to find
valueToFind := 6
// Use labeled outer loop
OuterLoop:
for i, row := range grid {
for j, value := range row {
fmt.Printf("Checking position [%d][%d] with value %d
", i, j, value)
if value == valueToFind {
fmt.Printf("Found %d at position [%d][%d]!
", valueToFind, i, j)
break OuterLoop
}
}
}
}
Output:
Checking position [0][0] with value 1
Checking position [0][1] with value 2
Checking position [0][2] with value 3
Checking position [1][0] with value 4
Checking position [1][1] with value 5
Checking position [1][2] with value 6
Found 6 at position [1][2]!
Visual Flow of Different Loop Types
Here's a diagram showing the execution flow of different types of loops in Go:
Real-world Applications
Example 1: Data Processing
This example shows how to process a dataset using loops to calculate the average temperature:
package main
import "fmt"
func main() {
temperatures := []float64{23.5, 25.1, 22.7, 26.8, 24.3, 27.1, 21.9}
var sum float64
for _, temp := range temperatures {
sum += temp
}
average := sum / float64(len(temperatures))
fmt.Printf("Average temperature: %.2f°C
", average)
// Find temperatures above average
fmt.Println("Days with above-average temperatures:")
for i, temp := range temperatures {
if temp > average {
fmt.Printf("Day %d: %.2f°C
", i+1, temp)
}
}
}
Output:
Average temperature: 24.49°C
Days with above-average temperatures:
Day 2: 25.10°C
Day 4: 26.80°C
Day 6: 27.10°C
Example 2: Building a Simple Menu System
Here's how loops can be used to create an interactive menu:
package main
import (
"fmt"
"os"
)
func main() {
for {
// Display menu
fmt.Println("
---- Task Manager ----")
fmt.Println("1. Add a new task")
fmt.Println("2. List all tasks")
fmt.Println("3. Mark task as complete")
fmt.Println("4. Exit")
fmt.Print("
Enter your choice (1-4): ")
var choice int
fmt.Scan(&choice)
switch choice {
case 1:
fmt.Println("Adding a new task...")
// Add task logic would go here
case 2:
fmt.Println("Listing all tasks...")
// List tasks logic would go here
case 3:
fmt.Println("Marking task as complete...")
// Complete task logic would go here
case 4:
fmt.Println("Exiting program. Goodbye!")
os.Exit(0)
default:
fmt.Println("Invalid choice! Please enter a number between 1 and 4.")
}
}
}
Common Pitfalls and Best Practices
Variable Scope
Variables declared inside a for loop are scoped to that loop's block:
for i := 0; i < 5; i++ {
// i is accessible here
}
// i is NOT accessible here
Loop Variable Capture
When using goroutines inside loops, be careful with variable capture:
// Incorrect
for i := 0; i < 5; i++ {
go func() {
fmt.Println(i) // Will likely print the final value of i multiple times
}()
}
// Correct
for i := 0; i < 5; i++ {
go func(val int) {
fmt.Println(val) // Will print the expected values
}(i)
}
Infinite Loop Detection
Go doesn't automatically detect infinite loops, so ensure your loop conditions eventually become false or that you have a break
statement that will be reached.
Performance Considerations
- For large collections, consider if your loop operation can be parallelized using goroutines.
- When iterating over large structures, avoid unnecessary memory allocations inside the loop.
- For simple iterations over integers, traditional for loops are generally more efficient than range-based loops.
Summary
Go provides a single, versatile for
loop construct that can be adapted to handle all common looping patterns:
- Traditional for loops:
for i := 0; i < n; i++ {}
- While-style loops:
for condition {}
- Infinite loops:
for {}
- For-each loops with range:
for index, value := range collection {}
Remember these key points:
- The
break
statement exits a loop completely - The
continue
statement skips to the next iteration - Labeled statements allow you to control outer loops from inner loops
- Variables declared in the loop initialization are scoped to the loop body
- Be cautious of variable capture in goroutines inside loops
Exercises
- Write a program that prints all even numbers between 1 and 20.
- Create a loop that counts down from 10 to 1, then prints "Blast off!".
- Write a program that computes the sum of all elements in an array of integers.
- Create a program that finds the largest number in a slice of integers using a loop.
- Write a nested loop that prints a simple pattern like a triangle or a square.
Additional Resources
- Go Tour: For loops
- Effective Go: For loops
- Go by Example: For loops
- Go Programming Language Specification
Happy coding with Go loops!
If you spot any mistakes on this website, please let me know at [email protected]. I’d greatly appreciate your feedback! :)