Skip to main content
The switch statement

The switch statement

6 minutes read

Filed underGo Programming Languageon

Go's switch is cleaner and more powerful than most languages. Learn how it handles multiple code paths, initialization, multi-condition cases, and fallthrough.

When there are too many paths

The if/else chain is fine for two or three conditions, but it degrades fast. By the fourth branch the structure becomes harder to scan, and readers lose track of what the central value actually is. The switch statement is the answer to this problem: it makes the subject of comparison explicit, groups each possible outcome into its own named case, and keeps the code flat.

Go's switch is more capable than the one you might know from C or Java. Cases don't fall through by default, each case is its own scope, a single case can match multiple values, and — like for — the statement supports an initialization clause. These small differences add up to a construct that is genuinely pleasant to work with.

Basic switch

The simplest form takes an expression and compares it against a list of values:

The switch evaluates day once and checks each case in order from top to bottom. The first matching case runs and control exits the entire switch — no break needed. If no case matches, default runs. The default case is optional and can appear anywhere in the list, though placing it last is conventional.

No implicit fall-through

In C and Java, forgetting a break at the end of a case causes execution to "fall through" into the next case — a notorious source of bugs. Go flips this default: each case stops automatically. Fall-through must be requested explicitly with the fallthrough keyword, covered later in this article.

Switch with initialization

Like for, the switch statement accepts an optional initialization clause separated from the expression by a semicolon. The variable declared in the init clause is scoped to the entire switch block, including all cases:

Here os is declared and assigned in the init clause, then used as the switch expression on the same line. Once the switch block ends, os goes out of scope. This pattern keeps the variable tightly contained — it does not leak into the surrounding function.

Each case is its own scope

Unlike many languages, each case in Go implicitly introduces its own code block. This means you can declare variables inside a case without worrying about collisions with other cases:

Both cases declare msg, and Go treats them as completely independent variables. In languages without per-case scoping, this would require explicit braces or cause a redeclaration error.

Matching multiple conditions in one case

A single case can list multiple values separated by commas. If the switch expression matches any of them, the case runs:

This is more readable than duplicating the case body or chaining conditions. Whenever two or more values share the same behavior, group them into one case.

Expressionless switch

Go allows omitting the switch expression entirely. When you do, it behaves like switch true — each case is evaluated as a boolean expression, and the first one that is true runs:

This form is a clean replacement for a long if/else if chain, especially when the conditions involve ranges or complex expressions rather than equality checks.

Expressionless switch vs if/else

The two forms are equivalent in behavior, but switch makes the intent clearer when you have three or more mutually exclusive branches. Use if/else for one or two conditions; reach for switch when the branches multiply.

The fallthrough keyword

Go's default — no fall-through — is almost always what you want. But occasionally you need a case to intentionally continue into the next one. The fallthrough keyword does exactly that:

Output:

positive greater than -10

When the first case matches and fallthrough is reached, execution transfers to the body of the next case unconditionally — it does not re-evaluate the next case's condition. This is an important detail: fallthrough is a blind jump into the next body, not a second condition check.

fallthrough skips condition evaluation

When fallthrough transfers control, the condition of the next case is not checked. If you need both conditions to hold, use a multi-condition case or nested logic instead. Surprising fallthrough chains are the Go equivalent of the C fall-through bug — use it sparingly.

Multi-condition cases vs fallthrough

Both features let a single code path handle multiple scenarios, but they serve different purposes and have different readability profiles:

Multi-condition casefallthrough
Conditions checkedAll values matched explicitlyOnly the first matching case
Next case conditionNot applicableSkipped — body runs unconditionally
ReadabilityClear intent, easy to scanLess obvious, requires mental tracking
Best forValues that share the same behaviorRare cases where cascading is genuinely needed

In practice, the vast majority of fallthrough uses can be replaced with a multi-condition case:

The multi-condition version states intent directly. The fallthrough chain forces the reader to trace through three cases to understand that they all do the same thing. Reserve fallthrough for the rare situation where cases genuinely need to cascade with distinct bodies.