Go deliberately has only one loop and a very regular switch; knowing their forms covers almost all control flow.
if has no parentheses but always needs braces. It can start with a short statement whose variables are scoped to the if/else: if n, err := strconv.Atoi(s); err == nil { ... }. This keeps temporary variables out of the surrounding scope and is used constantly with errors.
for is Go's only loop, in several shapes:
for i := 0; i < 10; i++ { }— classic three-part loop.for cond { }— a while loop;for { }loops forever.for i, v := range items { }— iterate slices, arrays, strings, maps and channels. Use_to ignore the index.for i := range 10 { }— since Go 1.22 you can range over an integer: 0 to 9.
Since Go 1.22 each iteration gets a fresh copy of the loop variables, so closures and goroutines capturing i see the value of that iteration.
break and continue work as expected; label the outer loop (outer: for ... then break outer) to exit nested loops.
switch compares a value against cases top to bottom and runs the first match. There is no fall-through by default — no break needed. A case can list several values (case "sat", "sun":), and a switch with no expression acts as a clean if/else chain: switch { case x < 0: ... case x == 0: ... }. Use the fallthrough keyword in the rare case you want to continue into the next case.
Example
package main
import (
"fmt"
"strconv"
)
func main() {
if n, err := strconv.Atoi("42"); err == nil {
fmt.Println("parsed", n) // parsed 42
}
for i := range 3 {
fmt.Print(i, " ") // 0 1 2
}
fmt.Println()
for _, day := range []string{"mon", "sat"} {
switch day {
case "sat", "sun":
fmt.Println(day, "weekend")
default:
fmt.Println(day, "weekday")
}
}
}Remember
forcovers classic, while, infinite and range loops- Use
if x, err := f(); err != nilto scope temporaries - switch cases don't fall through; list several values per case
Watch out for
- Writing
breakinside a switch inside a for loop expecting to leave the loop — it only leaves the switch; use a label.