In this lesson we cover Go control flow — how programs make decisions and repeat work. You will learn go if else for loop patterns that appear in every real Go codebase: branching with if and switch, and iterating with for in its classic, while-style, and range forms. If you completed Lesson 4 – Variables and Types, you already know how to store data; now we act on it.
Prerequisites: Lessons 1–4 of this series, especially Variables and Types and Basic Syntax. Estimated time: 40–50 minutes.
1. if and else Statements
The if statement runs a block when a condition is true. Go requires parentheses around the condition — unlike C — but does not require parentheses around the condition expression itself:
package main
import "fmt"
func main() {
score := 85
if score >= 90 {
fmt.Println("Grade: A")
} else if score >= 80 {
fmt.Println("Grade: B")
} else {
fmt.Println("Grade: C or below")
}
}
Key rules: the opening brace { must be on the same line as if (Go enforces this). Conditions must be boolean expressions — Go will not treat 0 or "" as false the way some languages do. This strictness prevents subtle bugs and makes intent obvious when you read code.
2. if with a Short Statement
Go allows a short statement before the condition, separated by a semicolon. The variable declared in that statement is scoped only to the if block (and its else branches):
package main
import (
"fmt"
"math"
)
func main() {
x := 16.0
if root := math.Sqrt(x); root > 3 {
fmt.Printf("Square root %.2f is greater than 3\n", root)
} else {
fmt.Printf("Square root %.2f is 3 or less\n", root)
}
// root is not visible here
}
This pattern is idiomatic when you need a temporary value only for the decision — for example, parsing input or calling a function that returns a result and an error. You will see if err := doSomething(); err != nil { ... } throughout Go code; we explore that error-handling style more when we cover functions.
3. switch Statements
switch compares a value against multiple cases. Unlike C, Go cases do not fall through unless you use fallthrough:
package main
import "fmt"
func main() {
day := "Wednesday"
switch day {
case "Monday", "Tuesday", "Wednesday", "Thursday", "Friday":
fmt.Println("Weekday")
case "Saturday", "Sunday":
fmt.Println("Weekend")
default:
fmt.Println("Unknown day")
}
}
Go also supports switch without a tag — each case is a boolean expression, useful as a cleaner alternative to long if else chains:
score := 72
switch {
case score >= 90:
fmt.Println("Excellent")
case score >= 70:
fmt.Println("Good")
default:
fmt.Println("Keep practicing")
}
Switch cases can use constants, strings, integers, and more. Because there is no automatic fall-through, you rarely need break — one less source of errors compared to C-style switches.
4. Classic for Loop
Go has one loop keyword: for. The classic three-part form mirrors C:
package main
import "fmt"
func main() {
sum := 0
for i := 1; i <= 5; i++ {
sum += i
}
fmt.Println("Sum 1..5 =", sum) // 15
}
The init statement, condition, and post statement are all optional. An infinite loop is written as for { } — use break inside to exit. Unlike Python's for i in range(n), Go's C-style loop gives you full control over the counter variable and step size.
5. While-Style for Loop
Go has no while keyword. A condition-only for loop acts like while in other languages:
package main
import "fmt"
func main() {
n := 1
for n < 100 {
n *= 2
}
fmt.Println("First power of 2 >= 100:", n) // 128
}
This form is common when you do not know how many iterations you need in advance — reading from a buffer, retrying a network call, or processing until a sentinel value appears. Combine with break and continue to skip the rest of an iteration or exit the loop early.
6. for range Loop
The range keyword iterates over slices, arrays, strings, maps, and channels. For a slice or array, you get an index and a copy of each element:
package main
import "fmt"
func main() {
languages := []string{"Go", "Python", "Rust"}
for index, lang := range languages {
fmt.Printf("%d: %s\n", index, lang)
}
// Index only — discard value with _
for i := range languages {
fmt.Println(i, languages[i])
}
}
When ranging over a string, the index is a byte offset and the value is a rune (Unicode code point). For maps, range yields key-value pairs in random order. We cover slices and maps in depth in later lessons; for now, treat range as the idiomatic way to visit every item in a collection.
7. Choosing the Right Construct
Use this quick reference when deciding which control structure fits:
| Goal | Construct | Example |
|---|---|---|
| Two-way branch | if else |
if x > 0 { ... } else { ... } |
| Scoped temp before test | if short statement |
if v := f(); v > 0 { ... } |
| Many discrete values | switch |
switch day { case "Mon": ... } |
| Counted iteration | Classic for |
for i := 0; i < n; i++ { ... } |
| Condition-driven loop | While-style for |
for condition { ... } |
| Collection iteration | for range |
for i, v := range items { ... } |
Go favors simplicity: one loop keyword, explicit conditions, and no hidden truthiness. If you learned control flow in Python, notice that Go's for range is the closest equivalent to for item in collection, while counted loops use the three-part for form instead of range(n).
8. Next Steps
You now understand go if else for loop control flow: branching, switch, and every form of the for loop. In the next lesson we cover functions — how to organize code into reusable blocks with parameters, return values, and defer.
Continue the series: Lesson 4 – Variables and Types · Lesson 6 – Functions
Browse all tutorials: Content Directory · Go Programming Hub
Frequently Asked Questions
Does Go have a while loop?
No. Use for condition { } without init or post statements. It behaves exactly like a while loop in other languages.
Do switch cases fall through in Go?
No, by default. Each case runs only its own block and then exits the switch. Use fallthrough explicitly if you truly need C-style fall-through — which is rare.
Can I modify the loop variable in a range loop?
The range value is a copy of each element. Changing it does not update the underlying slice. Use the index form for i := range s { s[i] = ... } to modify slice elements.
Want live Go or backend classes? Join Alkademy for instructor-led programming courses with hands-on projects.
[…] Previous: Lesson 5: Go Control Flow – if, else, switch, and for Loops […]