Mastering Go's Switch: Advanced Patterns and Common Pitfalls
This guide explores Go's versatile switch statement, covering basic syntax, initializer and value parts, literal true switches, short assignments, multiple case values, fallthrough behavior, default placement nuances, and type switches, all illustrated with clear code examples.
Basic Switch Syntax
Go's switch statement automatically breaks after a matching case, so explicit break statements are unnecessary.
func main() {
var i int = 1
switch i {
case 1:
fmt.Println("i is 1")
case 2:
fmt.Println("i is 2")
default:
fmt.Println("i is not 1 or 2")
}
}A switch can have an initializer, a value to test, both, or neither:
switch initializer; value {}
switch initializer {}
switch value {}
switch {}Using Literal Boolean Values
Switching on the literal true lets you treat each case as an independent condition:
switch true {
case a == 1 && b == 2:
fmt.Println("a is 1 and b is 2")
case a == 3:
fmt.Println("a is 3")
default:
fmt.Println("a is not 1 or 3")
}The same logic can be written without the explicit true:
switch {
case a == 1 && b == 2:
// ...
}Short Assignment in Switch
Like if, a switch can declare and initialize a variable that is scoped to the statement:
switch a := 1; a {
case 1:
fmt.Println("a is 1")
}
// equivalent to
if a := 1; a == 1 {
fmt.Println("a is 1")
}If only the initializer is provided, the value part defaults to true:
switch a := 1 {
case a == 1:
fmt.Println("a is 1")
case a == 2:
fmt.Println("a is 2")
}Multiple Values in a Single Case
Several constant values can be combined in one case, making the code more concise:
switch a := 1; a {
case 1, 2, 3:
fmt.Println("a is 1, 2 or 3")
}Writing separate cases without combined values leads to unexpected behavior because only the last case's statements are executed:
switch a := 1; a {
case 1:
case 2:
case 3:
fmt.Println("a is 1, 2 or 3")
}Using fallthrough
The fallthrough keyword forces execution to continue to the next case without evaluating its condition:
switch a := 1; a {
case 1:
fmt.Println("a is 1")
fallthrough
case 2:
fmt.Println("Now in case 2")
fallthrough
default:
fmt.Println("Neither 1 nor 2")
}When the last case uses fallthrough, it has no effect because there is no subsequent case.
Default Case Placement and Interaction with fallthrough
The default case can appear anywhere; it is still considered the fallback when no other case matches:
switch a := 1; a {
default:
fmt.Println("Neither 1 nor 2")
case 1:
fmt.Println("a is 1")
case 2:
fmt.Println("Now in case 2")
}Combining default with fallthrough allows execution to continue into a subsequent case:
switch a := 3; a {
default:
fmt.Println("Neither 1 nor 2")
fallthrough
case 1:
fmt.Println("a is 1")
case 2:
fmt.Println("Now in case 2")
}Type Switches
A switch can perform type assertions on an interface value, enabling different handling based on the concrete type:
func main() {
var i interface{} = "hello"
switch v := i.(type) {
case int:
fmt.Println("i is an int and its value is", v)
case string:
fmt.Println("i is a string and its value is", v)
default:
fmt.Println("Unknown type")
}
}Inside each case, v holds the value of i asserted to the matched type, allowing type‑specific operations.
Senior Brother's Insights
A public account focused on workplace, career growth, team management, and self-improvement. The author is the writer of books including 'SpringBoot Technology Insider' and 'Drools 8 Rule Engine: Core Technology and Practice'.
How this landed with the community
Was this worth your time?
0 Comments
Thoughtful readers leave field notes, pushback, and hard-won operational detail here.
