If and Switch in Go
Conditional logic in Go — no parentheses required, and a switch statement that doesn't fall through by default.
2 min read
Go's conditionals will feel immediately familiar if you've used any C-family language, with a few small syntax differences that trip people up exactly once before becoming second nature.
if statements
age := 20
if age >= 18 {
fmt.Println("adult")
} else if age >= 13 {
fmt.Println("teenager")
} else {
fmt.Println("child")
}Two things stand out immediately: there are no parentheses around the condition, and the braces are mandatory — you can't write a one-line if without them, even for a single statement. Go's formatter and compiler both enforce this, which eliminates an entire category of "the else attached to the wrong if" bugs.
The init statement
Go's if supports an optional initialization statement before the condition, scoped only to the if/else block:
if err := doSomething(); err != nil {
fmt.Println("failed:", err)
}err only exists inside this if and any attached else — it doesn't leak into the surrounding scope. This pattern is everywhere in idiomatic Go, especially paired with error handling, because it keeps the error variable's scope as tight as possible.
switch statements
switch day := 3; day {
case 1, 7:
fmt.Println("weekend")
case 2, 3, 4, 5, 6:
fmt.Println("weekday")
default:
fmt.Println("invalid day")
}A few differences from C-style switches matter here. Cases can list multiple values separated by commas. And critically, Go's cases don't fall through by default — each case automatically breaks after its block runs, unlike JavaScript, C, or Java, where forgetting a break is a classic bug. If you genuinely want fallthrough behavior, you opt in explicitly:
switch n := 1; n {
case 1:
fmt.Println("one")
fallthrough
case 2:
fmt.Println("two")
}
// prints both "one" and "two"Switch without a condition
A switch with no expression after it is a clean alternative to a long if/else if chain, since each case can be its own boolean condition:
score := 85
switch {
case score >= 90:
fmt.Println("A")
case score >= 80:
fmt.Println("B")
case score >= 70:
fmt.Println("C")
default:
fmt.Println("F")
}This reads more cleanly than the equivalent if/else if chain once you have more than two or three branches, and it's a common idiom in Go code.
Type switches
Go also supports switching on the dynamic type of an interface value — useful once you're working with interface{} (or its modern spelling, any):
func describe(i interface{}) {
switch v := i.(type) {
case int:
fmt.Println("int:", v)
case string:
fmt.Println("string:", v)
default:
fmt.Println("unknown type")
}
}This pattern comes up constantly once you're working with interfaces and generic-ish code, which the Data Structures section covers in more depth.
Between if, switch, and the loop constructs in the next lesson, that's the entire branching toolkit Go gives you — there's no ternary operator, and that's intentional. Go's designers considered condition ? a : b a readability trade Go shouldn't make; an explicit if/else is always the way.
Test what you just learned
4 quick questions. Get all of them right to unlock the next lesson.
You can take the quiz without an account — logging in just lets your result count toward your progress.