Go simplifies control flow down to three keywords: if, for, and switch. There is no while or do-while — for alone covers counted loops, condition-only loops, and infinite loops, depending on which clauses you omit. Parentheses around conditions are not just optional but idiomatically omitted; braces are mandatory even for single-statement bodies.
for: Go's only loop
The same for keyword handles every loop shape by simply omitting parts of its three clauses (init; condition; post):
for i := 0; i < 5; i++ { // classic counted loop
fmt.Println(i)
}
n := 0
for n < 3 { // condition only — this IS Go's "while"
n++
}
for { // no clauses — infinite loop
if n > 10 { break }
n++
}
for i, v := range []string{"a", "b", "c"} { // range over a slice
fmt.Println(i, v) // i = index, v = value
}if statements and the init shortcut
if never uses parentheses around its condition, and can carry an optional initializer statement before the condition, scoped only to the if/else chain — a pattern used constantly for error handling:
if err := doSomething(); err != nil {
return err // err is scoped to this if/else block only
}
if x := compute(); x > 10 {
fmt.Println("big")
} else if x > 0 {
fmt.Println("small")
} else {
fmt.Println("non-positive")
}switch without fallthrough
Go's switch breaks from the case automatically after each match — the opposite default of C or Java, where you must remember break. Falling through to the next case requires the explicit fallthrough keyword. A switch with no expression at all acts as a clean chain of if/else conditions, and switches can match multiple values or types in one case.
switch day {
case "Sat", "Sun":
fmt.Println("weekend")
default:
fmt.Println("weekday")
}
switch { // no expression: acts like if/else if/else
case score >= 90:
fmt.Println("A")
case score >= 80:
fmt.Println("B")
default:
fmt.Println("C or below")
}