Go Control Flow
Overview
Go's control flow for conditionals is intentionally minimal: if/else for branching and switch as a cleaner alternative to long if-else chains. No parentheses around conditions, braces always required. For loops, see [[Loops]].
if / else
The condition needs no parentheses. The opening brace must be on the same line as if — Go enforces this formatting.
x := 15
if x < 0 {
fmt.Println("negative")
} else if x == 0 {
fmt.Println("zero")
} else {
fmt.Println("positive")
}
// positive
if with Short Statement
Run a short initialisation statement before the condition. The variable declared is scoped to the entire if/else block — not accessible outside.
// v is only available inside the if/else block
if v := compute(); v > 100 {
fmt.Println("large:", v)
} else {
fmt.Println("small:", v)
}
// v is not accessible here
// Most common use: scoped error check
if err := doSomething(); err != nil {
log.Fatal(err)
}
Why useful: keeps error variables from polluting the surrounding scope.
switch
switch is a cleaner way to write a series of if/else comparisons. Go's switch auto-breaks — no fall-through by default. Cases need not be constants or integers.
os := "darwin"
switch os {
case "darwin":
fmt.Println("macOS")
case "linux":
fmt.Println("Linux")
case "windows":
fmt.Println("Windows")
default:
fmt.Printf("Unknown OS: %s\n", os)
}
switch with init statement
switch os := runtime.GOOS; os {
case "darwin":
fmt.Println("macOS")
default:
fmt.Println(os)
}
switch with no condition — replaces long if-else chains
Equivalent to switch true. Each case is an independent boolean expression — much cleaner than a chain of else if:
t := time.Now()
switch {
case t.Hour() < 12:
fmt.Println("Good morning!")
case t.Hour() < 17:
fmt.Println("Good afternoon.")
default:
fmt.Println("Good evening.")
}
Multiple values per case
switch day {
case "Saturday", "Sunday":
fmt.Println("Weekend")
default:
fmt.Println("Weekday")
}
fallthrough — explicit fall to next case
By default cases don't fall through. Use fallthrough to explicitly continue to the next case (unconditional — the next case's condition is not checked):
switch n {
case 1:
fmt.Println("one")
fallthrough
case 2:
fmt.Println("two or after one") // prints this
fallthrough
case 3:
fmt.Println("three or after two") // also prints this
}
Gotchas
| Gotcha | Detail |
|---|---|
| No parentheses around conditions | if (x > 0) is valid but the formatter removes them — just write if x > 0 |
| Opening brace must be on same line | if x > 0 \n { is a syntax error |
switch auto-breaks | No break needed between cases; fallthrough is the explicit opt-in |
fallthrough is unconditional | It falls through regardless of the next case's condition |
| Short-statement variable scope | if v := ...; cond — v is only alive inside the if/else block |