Skip to main content

Control Structures

Go has fewer control structures than languages like C or Java, but they are versatile.

If / Else

The syntax is similar to C, but parentheses () are not required around the condition, and braces {} are mandatory.
x := 10

if x > 5 {
    fmt.Println("x is big")
} else {
    fmt.Println("x is small")
}

If with Short Statement

You can execute a short statement before the condition. Variables declared here are scoped to the if block.
if v := math.Pow(x, n); v < lim {
    return v
} else {
    fmt.Printf("%g >= %g\n", v, lim)
}
// v is not available here

For Loops

Go has only one looping construct: the for loop. It can be used in three ways.

1. Standard C-style Loop

for i := 0; i < 10; i++ {
    fmt.Println(i)
}

2. While-style Loop

If you omit the init and post statements, it acts like a while loop.
sum := 1
for sum < 1000 {
    sum += sum
}

3. Infinite Loop

If you omit the condition, it loops forever.
for {
    // do something forever
    if condition {
        break // exit loop
    }
}

Switch Statements

Go’s switch is more powerful than in C.
  • No break needed (it’s implicit).
  • Cases don’t need to be constants or integers.
import "runtime"

switch os := runtime.GOOS; os {
case "darwin":
    fmt.Println("OS X.")
case "linux":
    fmt.Println("Linux.")
default:
    // freebsd, openbsd,
    // plan9, windows...
    fmt.Printf("%s.\n", os)
}

Switch with no condition

This is a clean way to write long if-then-else chains.
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.")
}

Defer

A defer statement defers the execution of a function until the surrounding function returns. The deferred call’s arguments are evaluated immediately, but the function call is not executed until the surrounding function returns.
func main() {
    defer fmt.Println("world")

    fmt.Println("hello")
}
// Output:
// hello
// world

Stacking Defers

Deferred function calls are pushed onto a stack. When a function returns, its deferred calls are executed in last-in-first-out order.
func main() {
    fmt.Println("counting")

    for i := 0; i < 4; i++ {
        defer fmt.Println(i)
    }

    fmt.Println("done")
}
// Output:
// counting
// done
// 3
// 2
// 1
// 0
This is extremely useful for resource cleanup (closing files, unlocking mutexes).
f, _ := os.Open("filename")
defer f.Close() // Will be called when function exits