Skip to content

Go Loops: For, While, and Control Flow

Overview

Master Go's powerful loop constructs and control flow mechanisms. This comprehensive guide covers the versatile for loop, while-style loops, and essential control statements like break and continue, building upon our foundation of data types and variables.

Key Points

  • Go has only one loop construct: the for loop
  • Multiple patterns: classic, while-style, infinite, and range loops
  • Powerful control flow with break and continue
  • Clean and readable iteration patterns
  • Efficient performance with proper loop design

Understanding Go's Loop Philosophy

Go simplifies loop constructs by providing a single, versatile for loop that can handle all iteration needs. This design promotes consistency and reduces complexity.

Loop Patterns in Go

graph TD
    A[Go For Loop] --> B[Classic For]
    A --> C[While-Style]
    A --> D[Infinite Loop]
    A --> E[Range Loop]
    B --> B1[Init; Condition; Post]
    C --> C1[Condition Only]
    D --> D1[No Conditions]
    E --> E1[Iterate Collections]
    style A fill:#555,stroke:#333,stroke-width:2px,color:#000

Classic For Loop

The classic for loop provides precise control over initialization, condition checking, and post-iteration operations.

Basic Structure

Classic For Loop Syntax

classic_for.go
package main

import "fmt"

func main() {
    for i := 0; i < 5; i++ {
        fmt.Printf("Iteration %d\n", i)
    }

    // Output:
    // Iteration 0
    // Iteration 1
    // Iteration 2
    // Iteration 3
    // Iteration 4
}

Three Components

  1. Init: i := 0 - executed once before the loop
  2. Condition: i < 5 - checked before each iteration
  3. Post: i++ - executed after each iteration
flexible_init.go
package main

import "fmt"

func main() {
    // Multiple variables in init
    for i, j := 0, 10; i < j; i, j = i+1, j-1 {
        fmt.Printf("i=%d, j=%d\n", i, j)
    }

    // Output:
    // i=0, j=10
    // i=1, j=9
    // i=2, j=8
    // i=3, j=7
    // i=4, j=6
}
step_sizes.go
package main

import "fmt"

func main() {
    // Increment by 2
    fmt.Println("Even numbers:")
    for i := 0; i <= 10; i += 2 {
        fmt.Printf("%d ", i)
    }
    fmt.Println()

    // Decrement
    fmt.Println("Countdown:")
    for i := 5; i >= 0; i-- {
        fmt.Printf("%d ", i)
    }
    fmt.Println()

    // Output:
    // Even numbers: 0 2 4 6 8 10
    // Countdown: 5 4 3 2 1 0
}

While-Style Loops: Simplified Iteration 🔁

Go's for loop can mimic traditional while loops by omitting the init and post statements.

While Loop Pattern

While-Style Loops

while_basic.go
package main

import "fmt"

func main() {
    i := 0
    for i < 5 {
        fmt.Printf("Count: %d\n", i)
        i++
    }

    // Output:
    // Count: 0
    // Count: 1
    // Count: 2
    // Count: 3
    // Count: 4
}

While Equivalent

This is equivalent to while (i < 5) in other languages.

input_processing.go
package main

import "fmt"

func main() {
    var input string

    for input != "quit" {
        fmt.Print("Enter command (or 'quit' to exit): ")
        fmt.Scanln(&input)

        if input != "quit" {
            fmt.Printf("You entered: %s\n", input)
        }
    }

    fmt.Println("Goodbye!")
}
condition_based.go
package main

import (
    "fmt"
    "math/rand"
)

func main() {
    target := 7
    attempts := 0

    for {
        guess := rand.Intn(10) + 1
        attempts++
        fmt.Printf("Attempt %d: Guessed %d\n", attempts, guess)

        if guess == target {
            fmt.Printf("Found target %d in %d attempts!\n", target, attempts)
            break
        }
    }
}

Infinite Loops: Continuous Processing ♾

Infinite loops are useful for servers, event handlers, and continuous processing scenarios.

Infinite Loop Patterns

infinite_basic.go
package main

import "fmt"

func main() {
    counter := 0
    for {
        fmt.Printf("Running... %d\n", counter)
        counter++

        if counter >= 3 {
            fmt.Println("Breaking out of infinite loop")
            break
        }
    }
}
server_loop.go
package main

import (
    "fmt"
    "time"
)

func main() {
    fmt.Println("Server starting...")

    for {
        // Simulate processing
        fmt.Println("Processing request...")
        time.Sleep(1 * time.Second)

        // In a real server, you'd handle actual requests here
        // This example will run forever (Ctrl+C to stop)
        break // Remove this to see infinite behavior
    }
}

Control Flow: Break and Continue 🚥

Control flow statements provide fine-grained control over loop execution.

Break Statement

The break statement immediately exits the loop.

Break Statement Usage

break_simple.go
package main

import "fmt"

func main() {
    for i := 0; i < 10; i++ {
        fmt.Printf("i = %d\n", i)

        if i == 5 {
            fmt.Println("Breaking at 5")
            break
        }
    }
    fmt.Println("Loop ended")

    // Output:
    // i = 0
    // i = 1
    // i = 2
    // i = 3
    // i = 4
    // i = 5
    // Breaking at 5
    // Loop ended
}
search_break.go
package main

import "fmt"

func main() {
    numbers := []int{1, 3, 7, 9, 12, 15, 18}
    target := 12

    for i, num := range numbers {
        if num == target {
            fmt.Printf("Found %d at index %d\n", target, i)
            break
        }
        fmt.Printf("Checking %d at index %d\n", num, i)
    }
}
nested_break.go
package main

import "fmt"

func main() {
    found := false

    for i := 0; i < 3 && !found; i++ {
        for j := 0; j < 3; j++ {
            fmt.Printf("i=%d, j=%d\n", i, j)

            if i == 1 && j == 1 {
                fmt.Println("Found target position!")
                found = true
                break // Only breaks inner loop
            }
        }
    }
}

Continue Statement

The continue statement skips the rest of the current iteration and moves to the next one.

Continue Statement Usage

continue_skip.go
package main

import "fmt"

func main() {
    fmt.Println("Odd numbers from 1 to 10:")
    for i := 1; i <= 10; i++ {
        if i%2 == 0 {
            continue // Skip even numbers
        }
        fmt.Printf("%d ", i)
    }
    fmt.Println()

    // Output: 1 3 5 7 9
}
data_validation.go
package main

import "fmt"

func main() {
    data := []int{1, -2, 3, 0, 5, -7, 8}

    fmt.Println("Processing positive numbers:")
    for i, value := range data {
        if value <= 0 {
            fmt.Printf("Skipping invalid value %d at index %d\n", value, i)
            continue
        }

        // Process valid data
        result := value * 2
        fmt.Printf("Processed %d -> %d\n", value, result)
    }
}
error_handling.go
package main

import (
    "fmt"
    "strconv"
)

func main() {
    inputs := []string{"1", "abc", "3", "def", "5"}

    for i, input := range inputs {
        num, err := strconv.Atoi(input)
        if err != nil {
            fmt.Printf("Error converting '%s' at index %d: %v\n", input, i, err)
            continue
        }

        fmt.Printf("Successfully converted '%s' to %d\n", input, num)
    }
}

Advanced Loop Patterns ⚙

Labeled Breaks and Continues

For complex nested loops, Go provides labeled breaks and continues.

Labeled Control Flow

labeled_break.go
package main

import "fmt"

func main() {
    fmt.Println("Searching in 2D array:")

outer:
    for i := 0; i < 3; i++ {
        for j := 0; j < 3; j++ {
            fmt.Printf("Checking position [%d][%d]\n", i, j)

            if i == 1 && j == 1 {
                fmt.Println("Found target! Breaking out of both loops")
                break outer
            }
        }
    }

    fmt.Println("Search completed")
}
labeled_continue.go
package main

import "fmt"

func main() {
    fmt.Println("Processing matrix rows:")

rowLoop:
    for i := 0; i < 3; i++ {
        fmt.Printf("Processing row %d:\n", i)

        for j := 0; j < 3; j++ {
            if j == 1 && i%2 == 0 {
                fmt.Printf("  Skipping rest of row %d\n", i)
                continue rowLoop
            }
            fmt.Printf("  Processing element [%d][%d]\n", i, j)
        }
    }
}

Loop Performance Optimization

Performance Considerations

performance_bounds.go
package main

import "fmt"

func main() {
    data := []int{1, 2, 3, 4, 5, 6, 7, 8, 9, 10}

    // Good: Calculate length once
    length := len(data)
    for i := 0; i < length; i++ {
        fmt.Printf("Processing %d\n", data[i])
    }

    // Even better: Use range for slices
    for i, value := range data {
        fmt.Printf("Index %d: %d\n", i, value)
    }
}
minimize_work.go
package main

import "fmt"

func main() {
    numbers := []int{1, 2, 3, 4, 5}

    // Pre-calculate expensive operations
    multiplier := 2
    prefix := "Number: "

    for _, num := range numbers {
        result := num * multiplier
        fmt.Printf("%s%d\n", prefix, result)
    }
}

Best Practices 📓

Loop Best Practices

  1. Choose the Right Pattern

    • Use classic for when you need precise control
    • Use while-style for condition-based loops
    • Use range for collections (covered in Range documentation)
  2. Control Flow Guidelines

    • Use break to exit loops early
    • Use continue to skip iterations
    • Use labeled breaks/continues for nested loops
  3. Performance Tips

    • Pre-calculate loop bounds when possible
    • Minimize work inside loop bodies
    • Consider loop unrolling for critical paths
  4. Readability

    • Use descriptive variable names
    • Keep loop bodies concise
    • Comment complex loop logic

Common Pitfalls

  • Infinite Loops: Always ensure loop conditions can become false
  • Off-by-One Errors: Be careful with < vs <= conditions
  • Modifying Loop Variables: Avoid changing loop counters inside the loop body
  • Nested Loop Complexity: Consider extracting inner loops into functions

Quick Reference 📑

Key Takeaways

  1. Single Loop Construct: Go uses only for loops for all iteration needs
  2. Multiple Patterns: Classic, while-style, infinite, and range loops
  3. Control Flow: break and continue provide fine-grained control
  4. Labels: Use labeled breaks/continues for complex nested scenarios
  5. Performance: Choose appropriate patterns and optimize loop bodies

Remember

"Go's unified loop approach promotes consistency and simplicity. Master the for loop patterns and you'll handle any iteration scenario efficiently."