switch

switch is Go's compact alternative to a long if / else if / else chain. It takes an expression, compares it against each case, and runs the first matching branch. Unlike C and Java, cases do not fall through by default: the matched branch runs, and execution leaves the switch.

A basic switch

day := "Sat"

switch day {
case "Sat", "Sun":
    fmt.Println("weekend")
case "Mon", "Tue", "Wed", "Thu", "Fri":
    fmt.Println("weekday")
default:
    fmt.Println("unknown day")
}

A few things to notice:

  • Cases can list multiple values separated by commas. "Sat", "Sun" means "match either".
  • There is no break at the end of each case. The break is implicit.
  • default runs when no case matched. It is optional; leave it out if "unhandled value" is not a case you care about.

Cases are checked top-to-bottom and the first match wins; subsequent cases are not evaluated.

Expressionless switch

The basic switch works when you are comparing one value against a list. But a lot of real branching looks more like this:

hour := 14

if hour < 12 {
    fmt.Println("morning")
} else if hour < 18 {
    fmt.Println("afternoon")
} else {
    fmt.Println("evening")
}

That works, but reads as a chain of independent ifs that happen to share a variable. Drop the expression after switch and the same logic gets a cleaner shape:

switch {
case hour < 12:
    fmt.Println("morning")
case hour < 18:
    fmt.Println("afternoon")
default:
    fmt.Println("evening")
}

Each case is its own boolean expression. The first true case runs, the rest are skipped. This is the form you reach for when you are testing different conditions rather than comparing one value against a list, and it often reads cleaner than a long if / else if / else chain.

Short statement, like if

switch supports a short statement that scopes a variable to the switch block, same shape as the one you saw for if:

switch n := 10; {
case n < 0:
    fmt.Println("negative")
case n == 0:
    fmt.Println("zero")
default:
    fmt.Println("positive")
}
// n is out of scope here

Leaving the part after the semicolon empty gives you a short-statement + expressionless combination, which is often the cleanest shape for "compute once, then branch on conditions".

switch n := 10; {
case n > 0:
    fmt.Println("positive")
}
fmt.Println(n)          // compile error: undefined: n

fallthrough, the opt-in version of C's default behaviour

If you genuinely want a case to continue into the next one (rare), say so explicitly with fallthrough:

switch n := 1; n {
case 1:
    fmt.Println("one")
    fallthrough
case 2:
    fmt.Println("two")
case 3:
    fmt.Println("three")
}
// prints: one, then two

fallthrough jumps to the next case unconditionally: it does NOT re-check that case's value. That is why this prints two even though n is 1. The "no fallthrough by default" rule is one of Go's quiet improvements over C; reach for fallthrough only when you really mean it.

When to pick switch over if-else
  • Three or more comparisons of one value: switch reads better than an if/else-if chain.
  • Three or more unrelated boolean tests: the expressionless switch form is still cleaner than the chain.
  • Two branches, one condition: stick with if / else. switch starts paying off once there are more branches.
Task

The starter declares code := 404. Use an expressionless switch to print a category for the HTTP status code:

  • "success" if code is 200 or 201
  • "redirect" if code is 301 or 302
  • "client error" if code >= 400 and code < 500
  • "server error" if code >= 500
  • "unknown" otherwise

Each case will be a boolean expression (since the ranges cannot be written as value comparisons).

Expected output
client error