Chapter 37: Go switch
Go switch statement” in tutorials, they usually mean:
- how switch works in Go
- how it is very different from switch in C, Java, JavaScript, Python match, etc.
- why Go developers love it and use it a lot more often than in most other languages
Let’s go through everything step by step like we’re sitting together with VS Code open — slowly, with many real examples, style notes, common patterns, gotchas, and why Go made each decision.
1. Basic Syntax – Very Clean & Safe
|
0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 |
switch expression { case value1: // code case value2, value3: // code for multiple matching values case value4: // code default: // runs if nothing matched } |
Important rules (compiler enforces most of them):
- No mandatory parentheses around the expression → switch day { ← correct → switch (day) { ← legal but non-idiomatic
- Braces {}not required if only one statement per case → single-line cases are written without braces
- No automatic fallthrough — each case breaks automatically → no need for break (big difference from C/Java)
- You can have multiple values in one case (comma-separated)
- default is optional and can be anywhere (but usually last)
2. Simple Example – Weekday Classifier
|
0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 |
package main import ( "fmt" "time" ) func main() { today := time.Now().Weekday() switch today { case time.Monday, time.Tuesday, time.Wednesday, time.Thursday, time.Friday: fmt.Println("Weekday — work day 💼") case time.Saturday, time.Sunday: fmt.Println("Weekend — relax time! 🏖️") default: fmt.Println("What kind of day is this?!") } } |
3. The Most Important Feature: Expressionless switch (Type Switch / Tagless Switch)
This is extremely common in real Go code — you’ll see it every day.
|
0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 |
var i interface{} = "hello" // can be anything switch v := i.(type) { // type switch case int: fmt.Printf("Integer: %d\n", v) case string: fmt.Printf("String: %q\n", v) case bool: fmt.Printf("Boolean: %t\n", v) case nil: fmt.Println("Nil value") default: fmt.Printf("Unknown type: %T\n", v) } |
Another very common use — tagless switch (just conditions)
|
0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 |
score := 82 switch { case score >= 90: fmt.Println("Grade: A – Outstanding!") case score >= 80: fmt.Println("Grade: B – Very good") case score >= 70: fmt.Println("Grade: C – Good") case score >= 60: fmt.Println("Grade: D – Pass") default: fmt.Println("Grade: F – Try again") } |
Why tagless switch is so loved:
- Reads like a clean if-else if chain
- But more structured and easier to scan
- No duplication of the tested variable
4. Fallthrough – Rare, Explicit, and Usually Avoided
Unlike C/Java, fallthrough is not automatic — you must write fallthrough
|
0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 |
grade := "B" switch grade { case "A": fmt.Println("Excellent") fallthrough case "B": fmt.Println("Very good") case "C": fmt.Println("Good") default: fmt.Println("Needs improvement") } |
→ If grade == “A”, it will print both “Excellent” and “Very good”
Community advice 2025–2026:
- Use fallthroughvery rarely
- Most of the time when you want fallthrough behavior → better to list multiple values in one case → case “A”, “A+”, “A-“:
5. Idiomatic Patterns You Will See Every Day
Pattern 1: Error kind / status code handling
|
0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 |
switch err.(type) { case *os.PathError: fmt.Println("Path error") case *os.PermissionError: fmt.Println("Permission denied") case nil: // success default: fmt.Println("Unknown error") } |
Pattern 2: HTTP status code response
|
0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 |
switch statusCode { case 200, 201, 204: fmt.Println("Success") case 400, 401, 403, 404: fmt.Println("Client error") case 500, 502, 503, 504: fmt.Println("Server error") default: fmt.Println("Unknown status") } |
Pattern 3: Enum-like with constants + tagless switch
|
0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 |
const ( StatePending = "pending" StateRunning = "running" StateFailed = "failed" StateDone = "done" ) switch state { case StatePending: fmt.Println("Waiting to start") case StateRunning: fmt.Println("In progress") case StateFailed: fmt.Println("Failed – check logs") case StateDone: fmt.Println("Completed") default: fmt.Println("Unknown state") } |
6. Quick Practice – Try These
- Write a tagless switch that classifies age into: Child (<13), Teen (13–19), Young adult (20–35), Adult (36–60), Senior (>60)
- Write a type switch that handles different interface{} values and prints something meaningful
- Write a switch that handles HTTP-like status codes (200, 404, 500, etc.)
Which style do you like more — switch with expression or tagless switch?
Any part still confusing?
- Why no automatic fallthrough (Go philosophy)?
- When to prefer switch vs long if-else if chain?
- How to use fallthrough safely?
- Or ready to move to for loop next?
Keep writing small switch statements — they are one of the cleanest ways to handle multi-way decisions in Go and you’ll use them every single day.
You’re progressing beautifully — keep asking! 💪🇮🇳🚀
