Fundamentals

Control Statements

In Go, there are exactly three tools you need to know to control the flow of your program.

for loop

A for loop has three components:

  • 'init' → runs once before the loop
  • 'condition' → checked before each iteration
  • 'post' → runs after each iteration

Variables declared in the 'init' are scoped to the loop.

The loop exits when the condition becomes false.

for initialization; condition; post {
    // code block
}

Standard For Loop

for i := 0; i < 5; i++ { }

The init and post are optional.

func main() {
    sum := 1
    for ; sum < 1000; {
        sum += sum
    }
    fmt.Println(sum)
}

For as While

The designers of Go hated having multiple ways to do the exact same thing. So, they fired the while loop and the do-while loop, and gave all their jobs to the for loop!

At that point you can drop the semicolons: C's while is spelled for in Go.

func main() {
    sum := 1
    for sum < 1000 {
        sum += sum
    }
    fmt.Println(sum)
}

Infinite Loop

If you just write for {} with no conditions, it loops forever.

func main() {
    for {
    }
}

We use this all the time in backend engineering for servers that need to constantly listen for incoming web traffic!

if and else

Unlike many languages:

  • Go does not use parentheses () around conditions
  • Go always requires braces {} for the block

This is the same style used in for loops.

main.go
package main

import "fmt"

func main() {
    score := 85

    if score >= 90 {
        fmt.Println("Grade: A")
    } else if score >= 75 {
        fmt.Println("Grade: B")
    } else {
        fmt.Println("Grade: C")
    }
}
The else if and else keywords must start on the exact same line as the closing brace } of the previous block.

if with a short statement

Go allows you to declare a variable right before the condition, separated by a semicolon. This keeps your code clean because the variable only exists inside the if block:

// Calculate the total, then immediately check if it's > 100
if total := 50 * 3; total > 100 {
    fmt.Println("You are eligible for free shipping!")
}
Variables declared in the short statement are scoped to the entire if construct.
They are accessible within:
  • the if block
  • any associated else or else if blocks

switch statement

Go’s switch works similarly to other languages, but with a few important differences.

First, Go automatically stops after the matched case.

Unlike languages like C or Java, you don’t need to write a break statement. Only the selected case runs.

Second, case values are more flexible.
They don’t have to be constants, and they are not limited to integers. You can use expressions or other types as well.

switch expression {
    case value1:
        // code
    case value2:
        // code
    default:
        // fallback
}

Switch Without Condition

  • A switch without a condition behaves like switch true.
  • Each case is evaluated as a boolean expression, and the first true condition is executed.
  • This provides a cleaner alternative to long if-else chains.

Defer

defer schedules a function call to run after the surrounding function (the function it is written inside) finishes execution.

The arguments are evaluated immediately when defer is encountered, but the function call itself is delayed.

Deferred calls are pushed onto a stack and executed in last-in-first-out (LIFO) order when the function returns.

>>> starting
    done
    5
    4
    3
    2
    1
package main

import "fmt"

func main() {
    fmt.Println("starting")

    for i := 1; i < 6; i++ {
        defer fmt.Println(i)
    }

    fmt.Println("done")
}

To learn more about defer statements read this blog post.

Copyright © 2026