Control Flow Basics
10 examples to get you started with Control Flow - 7 basic and 3 intermediate.
Search across all documentation pages
10 examples to get you started with Control Flow - 7 basic and 3 intermediate.
mkdir flow && cd flow && go mod init example.com/flow.main.go and run with go run ..Branch on a boolean condition.
package main
import "fmt"
func main() {
n := 7
if n%2 == 0 {
fmt.Println("even")
} else {
fmt.Println("odd")
}
}if does not need parentheses around the condition.Related: if with Initialization & switch Patterns - init clauses and switch forms
The classic three-part header: init, condition, post.
package main
import "fmt"
func main() {
sum := 0
for i := 0; i < 5; i++ {
sum += i
}
fmt.Println(sum) // 10
}while keyword - this is the only loop keyword.i is scoped to the for statement.for shapes shown in later examples.Related: for Loop Variants & range Semantics - all
forforms
Iterate index and value together.
package main
import "fmt"
func main() {
langs := []string{"Go", "Rust", "Zig"}
for i, name := range langs {
fmt.Println(i, name)
}
}range works on slices, arrays, maps, channels, and strings._ to ignore index or value: for _, name := range langs.Related: for Loop Variants & range Semantics - per-collection semantics
Match a value against multiple cases.
package main
import "fmt"
func main() {
day := "Mon"
switch day {
case "Sat", "Sun":
fmt.Println("weekend")
default:
fmt.Println("weekday")
}
}default runs when no case matches.Related: if with Initialization & switch Patterns - tagless and type switches
Bind a temporary variable scoped to the if block.
package main
import (
"fmt"
"strconv"
)
func main() {
if n, err := strconv.Atoi("42"); err != nil {
fmt.Println("parse error:", err)
} else {
fmt.Println("parsed:", n)
}
}if and else blocks.Related: Go Control Flow: Expression-Oriented Design - why init clauses matter
Schedule a call to run when the function returns.
package main
import "fmt"
func main() {
defer fmt.Println("cleanup")
fmt.Println("work")
}defer executes on function exit, including panic unwind.defer f.Close() immediately after a successful Open().Related: defer, panic & recover - defer stack and recovery
Skip an iteration or exit the loop early.
package main
import "fmt"
func main() {
for i := 0; i < 10; i++ {
if i%2 == 0 {
continue
}
if i > 5 {
break
}
fmt.Println(i)
}
}continue jumps to the next iteration.break exits the innermost for, switch, or select.break/continue to outer loops (see intermediate example).Related: break, continue & Labeled Control Flow - labeled exits
Branch on dynamic type inside an interface value.
package main
import "fmt"
func describe(v any) {
switch x := v.(type) {
case int:
fmt.Println("int", x)
case string:
fmt.Println("string", x)
default:
fmt.Printf("other %T\n", x)
}
}
func main() {
describe(42)
describe("hi")
}v.(type) is only allowed in a switch statement.x holds the typed value in each case.any when the set of types is known.Related: if with Initialization & switch Patterns - type switch patterns
Exit an outer loop without a helper flag.
package main
import "fmt"
func main() {
outer:
for i := 0; i < 3; i++ {
for j := 0; j < 3; j++ {
if i*j == 4 {
break outer
}
fmt.Println(i, j)
}
}
}for, switch, or select statement.continue outer skips to the next iteration of the labeled loop.Related: break, continue & Labeled Control Flow - when labels help
Recover stops panic unwinding inside a deferred function.
package main
import "fmt"
func mayPanic() {
defer func() {
if r := recover(); r != nil {
fmt.Println("recovered:", r)
}
}()
panic("boom")
}
func main() {
mayPanic()
fmt.Println("main continues")
}recover returns nil unless called from a deferred function during panic.error, not panic.Related: Control Flow in HTTP Middleware - panic-safe handlers
Stack versions: This page was written for Go 1.26.x (Green Tea GC default, go fix modernizers - verify patch at build), chi (latest - verify at build), gin (latest - verify at build), echo (latest - verify at build), google.golang.org/grpc (latest - verify at build), sigs.k8s.io/controller-runtime (latest - verify at build), kubebuilder (latest - verify at build), tinygo (latest - verify board targets at build), wazero (latest - verify at build), and golangci-lint (latest - verify linter set at build).
Reviewed by Chris St. John·Last updated Jul 18, 2026