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
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.
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")
}
}
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!")
}
if construct.They are accessible within:- the
ifblock - any associated
elseorelse ifblocks
switch statement
Go’s switch works similarly to other languages, but with a few important differences.
First, Go automatically stops after the matched case.
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
}
serverRegion := "US-East"
switch serverRegion {
case "US-East", "US-West":
fmt.Println("Routing to North American servers.")
case "EU-Central":
fmt.Println("Routing to European servers.")
default:
fmt.Println("Routing to global fallback server.")
}
switch region := "US-East"; region {
case "US-East", "US-West":
fmt.Println("North America")
default:
fmt.Println("Other region")
}
serverRegion := "US-East"
switch {
case serverRegion == "US-East":
fmt.Println("Primary US server")
case serverRegion == "EU-Central":
fmt.Println("EU server")
default:
fmt.Println("Fallback server")
}
Switch Without Condition
- A
switchwithout a condition behaves likeswitch true. - Each
caseis evaluated as a boolean expression, and the first true condition is executed. - This provides a cleaner alternative to long
if-elsechains.
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.