Learn Go
beginner1 min read

Control Flow

Go keeps control flow simple: if, for, and switch cover all the ground that other languages handle with additional keywords like while, do, and foreach.

If / Else

The condition requires no parentheses, but the braces are mandatory:

package main
 
import "fmt"
 
func classify(n int) string {
    if n < 0 {
        return "negative"
    } else if n == 0 {
        return "zero"
    } else {
        return "positive"
    }
}
 
func main() {
    fmt.Println(classify(-5)) // negative
    fmt.Println(classify(0))  // zero
    fmt.Println(classify(7))  // positive
}

Initialisation Statement

if accepts an optional short statement before the condition. Variables declared here are scoped to the if/else block:

package main
 
import (
    "fmt"
    "strconv"
)
 
func parseAndDouble(s string) {
    if n, err := strconv.Atoi(s); err == nil {
        fmt.Println(n * 2)
    } else {
        fmt.Println("not a number:", err)
    }
}
 
func main() {
    parseAndDouble("21")   // 42
    parseAndDouble("oops") // not a number: ...
}

The for Loop

Go has exactly one looping keyword: for. It covers every looping pattern:

package main
 
import "fmt"
 
func main() {
    // Classic three-component loop
    for i := 0; i < 5; i++ {
        fmt.Print(i, " ")
    }
    fmt.Println()
 
    // Condition-only (equivalent to while)
    n := 1
    for n < 100 {
        n *= 2
    }
    fmt.Println(n) // 128
 
    // Infinite loop — use break to exit
    count := 0
    for {
        count++
        if count == 3 {
            break
        }
    }
    fmt.Println(count) // 3
}

Idiomatic Go: Go has no while keyword. Use for condition { } as a while loop and for { } as an infinite loop.

Range

The range form iterates over slices, arrays, maps, strings, and channels:

package main
 
import "fmt"
 
func main() {
    fruits := []string{"apple", "banana", "cherry"}
 
    for i, fruit := range fruits {
        fmt.Printf("%d: %s\n", i, fruit)
    }
 
    // Ignore the index with _
    for _, fruit := range fruits {
        fmt.Println(fruit)
    }
}

Switch

Go's switch does not fall through by default (unlike C/Java). Each case is independent:

package main
 
import "fmt"
 
func dayType(day string) string {
    switch day {
    case "Saturday", "Sunday":
        return "weekend"
    case "Monday", "Tuesday", "Wednesday", "Thursday", "Friday":
        return "weekday"
    default:
        return "unknown"
    }
}
 
func main() {
    fmt.Println(dayType("Monday"))   // weekday
    fmt.Println(dayType("Saturday")) // weekend
}

Switch with No Condition

A switch with no condition is a cleaner alternative to a chain of if/else if:

package main
 
import "fmt"
 
func score(n int) string {
    switch {
    case n >= 90:
        return "A"
    case n >= 80:
        return "B"
    case n >= 70:
        return "C"
    default:
        return "F"
    }
}
 
func main() {
    fmt.Println(score(95)) // A
    fmt.Println(score(82)) // B
    fmt.Println(score(65)) // F
}

Fallthrough

Use fallthrough explicitly when you want the next case to execute as well:

package main
 
import "fmt"
 
func main() {
    n := 2
    switch n {
    case 1:
        fmt.Println("one")
        fallthrough
    case 2:
        fmt.Println("two")
        fallthrough
    case 3:
        fmt.Println("three")
    case 4:
        fmt.Println("four")
    }
    // Prints: two, three
}

break and continue

Labels allow breaking out of nested loops:

package main
 
import "fmt"
 
func main() {
outer:
    for i := 0; i < 3; i++ {
        for j := 0; j < 3; j++ {
            if i == 1 && j == 1 {
                break outer
            }
            fmt.Println(i, j)
        }
    }
}

Key Takeaways