Go Switch Statements
Switch statements in Go are powerful and flexible constructs that provide an elegant way to handle multiple conditions and make your code more readable and maintainable. Unlike many other programming languages, Go's switch statements have unique characteristics that make them particularly useful for various programming scenarios. This comprehensive guide will teach you everything you need to know about Go's switch statements, from basic expression switches to advanced type switches and complex pattern matching.
Understanding Switch Statements in Go
What Are Switch Statements?
Switch statements allow you to compare a value against multiple possible cases and execute different code blocks based on the match. They provide a cleaner and more readable alternative to long chains of if/else
statements, especially when dealing with multiple discrete values.
Go's Unique Approach to Switch Statements
Go's switch statements have several distinctive features that set them apart from other programming languages:
Expression Switches
Go allows you to switch on expressions, not just values, making switch statements more flexible and powerful.
Type Switches
Go provides special type switches that allow you to switch based on the type of an interface value, enabling dynamic type checking and conversion.
Automatic Break Behavior
Unlike languages like C, Java, or JavaScript, Go's switch statements don't fall through to the next case by default, eliminating the need for explicit break
statements.
Optional Expression
Go allows you to omit the switch expression, creating a cleaner alternative to if/else
chains.
Fallthrough Control
Go provides explicit fallthrough
statements when you need the traditional fall-through behavior.
Expression Switches
Basic Expression Switch
The most common type of switch statement in Go is the expression switch, which compares a value against multiple cases.
package main
import "fmt"
func main() {
// Basic expression switch
day := "Monday"
switch day {
case "Monday":
fmt.Println("Start of the work week")
case "Tuesday":
fmt.Println("Second day of work")
case "Wednesday":
fmt.Println("Mid-week")
case "Thursday":
fmt.Println("Almost Friday")
case "Friday":
fmt.Println("TGIF!")
case "Saturday", "Sunday":
fmt.Println("Weekend!")
default:
fmt.Println("Unknown day")
}
// Switch with integer values
score := 85
switch score {
case 90, 91, 92, 93, 94, 95, 96, 97, 98, 99, 100:
fmt.Println("Grade: A")
case 80, 81, 82, 83, 84, 85, 86, 87, 88, 89:
fmt.Println("Grade: B")
case 70, 71, 72, 73, 74, 75, 76, 77, 78, 79:
fmt.Println("Grade: C")
case 60, 61, 62, 63, 64, 65, 66, 67, 68, 69:
fmt.Println("Grade: D")
default:
fmt.Println("Grade: F")
}
// Switch with character values
grade := 'B'
switch grade {
case 'A', 'a':
fmt.Println("Excellent!")
case 'B', 'b':
fmt.Println("Good job!")
case 'C', 'c':
fmt.Println("Satisfactory")
case 'D', 'd':
fmt.Println("Needs improvement")
case 'F', 'f':
fmt.Println("Failed")
default:
fmt.Println("Invalid grade")
}
}
Switch with Expressions
Go allows you to use expressions in both the switch statement and the case values, making switch statements extremely flexible.
package main
import "fmt"
func main() {
// Switch with expressions
age := 25
switch {
case age < 13:
fmt.Println("Child")
case age < 20:
fmt.Println("Teenager")
case age < 60:
fmt.Println("Adult")
default:
fmt.Println("Senior")
}
// Switch with calculated expressions
score := 85
attendance := 95
switch {
case score >= 90 && attendance >= 90:
fmt.Println("Honor roll student")
case score >= 80 && attendance >= 80:
fmt.Println("Good student")
case score >= 70 && attendance >= 70:
fmt.Println("Average student")
case score >= 60 && attendance >= 60:
fmt.Println("Below average student")
default:
fmt.Println("Needs improvement")
}
// Switch with function calls
temperature := 25
humidity := 60
switch {
case temperature > 30 && humidity > 70:
fmt.Println("Hot and humid - stay indoors!")
case temperature > 30:
fmt.Println("Hot day - stay hydrated!")
case temperature > 20 && humidity < 50:
fmt.Println("Perfect weather for outdoor activities!")
case temperature > 10:
fmt.Println("Pleasant weather")
default:
fmt.Println("Cool weather - dress warmly")
}
}
Switch with Variable Declaration
Go allows you to declare variables in the switch statement, similar to the if
statement, which is particularly useful for function calls that return values.
package main
import (
"fmt"
"strconv"
)
func main() {
// Switch with variable declaration
userInput := "42"
switch num, err := strconv.Atoi(userInput); {
case err != nil:
fmt.Printf("Error converting '%s': %v\n", userInput, err)
case num < 0:
fmt.Printf("Negative number: %d\n", num)
case num == 0:
fmt.Println("Zero")
case num > 0 && num <= 10:
fmt.Printf("Small positive number: %d\n", num)
case num > 10 && num <= 100:
fmt.Printf("Medium positive number: %d\n", num)
default:
fmt.Printf("Large positive number: %d\n", num)
}
// Switch with multiple variable declarations
x, y := 10, 20
switch sum := x + y; {
case sum < 20:
fmt.Printf("Small sum: %d\n", sum)
case sum < 50:
fmt.Printf("Medium sum: %d\n", sum)
default:
fmt.Printf("Large sum: %d\n", sum)
}
// Switch with type checking
var value interface{} = 42
switch v := value.(type) {
case int:
fmt.Printf("Integer value: %d\n", v)
case float64:
fmt.Printf("Float value: %.2f\n", v)
case string:
fmt.Printf("String value: %s\n", v)
default:
fmt.Printf("Unknown type: %T\n", v)
}
}
Multiple Case Values
Go allows you to specify multiple values in a single case, separated by commas, making your code more concise and readable.
package main
import "fmt"
func main() {
// Multiple case values
month := "December"
switch month {
case "December", "January", "February":
fmt.Println("Winter season")
case "March", "April", "May":
fmt.Println("Spring season")
case "June", "July", "August":
fmt.Println("Summer season")
case "September", "October", "November":
fmt.Println("Autumn season")
default:
fmt.Println("Unknown month")
}
// Multiple case values with different types
var value interface{} = "hello"
switch value {
case "hello", "hi", "hey":
fmt.Println("Greeting")
case 1, 2, 3, 4, 5:
fmt.Println("Small number")
case true, false:
fmt.Println("Boolean value")
default:
fmt.Println("Other value")
}
// Multiple case values with expressions
score := 85
switch {
case score >= 90:
fmt.Println("Grade: A")
case score >= 80, score >= 70 && score < 80:
fmt.Println("Grade: B or C")
case score >= 60:
fmt.Println("Grade: D")
default:
fmt.Println("Grade: F")
}
}
Fallthrough Behavior
Default No Fallthrough
Unlike many other programming languages, Go's switch statements don't fall through to the next case by default, which eliminates common bugs and makes code more predictable.
package main
import "fmt"
func main() {
// Default no fallthrough behavior
day := "Monday"
switch day {
case "Monday":
fmt.Println("Monday: Start of work week")
// No fallthrough - execution stops here
case "Tuesday":
fmt.Println("Tuesday: Second day")
// No fallthrough - execution stops here
case "Wednesday":
fmt.Println("Wednesday: Mid-week")
// No fallthrough - execution stops here
case "Thursday":
fmt.Println("Thursday: Almost Friday")
// No fallthrough - execution stops here
case "Friday":
fmt.Println("Friday: TGIF!")
// No fallthrough - execution stops here
case "Saturday", "Sunday":
fmt.Println("Weekend!")
// No fallthrough - execution stops here
default:
fmt.Println("Unknown day")
}
// Comparison with if/else chain
if day == "Monday" {
fmt.Println("Monday: Start of work week")
} else if day == "Tuesday" {
fmt.Println("Tuesday: Second day")
} else if day == "Wednesday" {
fmt.Println("Wednesday: Mid-week")
} else if day == "Thursday" {
fmt.Println("Thursday: Almost Friday")
} else if day == "Friday" {
fmt.Println("Friday: TGIF!")
} else if day == "Saturday" || day == "Sunday" {
fmt.Println("Weekend!")
} else {
fmt.Println("Unknown day")
}
}
Explicit Fallthrough
When you need the traditional fall-through behavior, Go provides the fallthrough
statement to explicitly continue execution to the next case.
package main
import "fmt"
func main() {
// Explicit fallthrough
score := 85
switch score {
case 100:
fmt.Println("Perfect score!")
fallthrough
case 90, 91, 92, 93, 94, 95, 96, 97, 98, 99:
fmt.Println("Grade: A")
fallthrough
case 80, 81, 82, 83, 84, 85, 86, 87, 88, 89:
fmt.Println("Grade: B")
fallthrough
case 70, 71, 72, 73, 74, 75, 76, 77, 78, 79:
fmt.Println("Grade: C")
// No fallthrough - execution stops here
case 60, 61, 62, 63, 64, 65, 66, 67, 68, 69:
fmt.Println("Grade: D")
default:
fmt.Println("Grade: F")
}
// Fallthrough with conditions
userType := "premium"
switch userType {
case "vip":
fmt.Println("VIP user benefits:")
fallthrough
case "premium":
fmt.Println("Premium user benefits:")
fallthrough
case "standard":
fmt.Println("Standard user benefits:")
fallthrough
default:
fmt.Println("Basic user benefits:")
}
// Conditional fallthrough
value := 5
switch value {
case 1, 2, 3:
fmt.Println("Small number")
if value == 3 {
fallthrough // Only fall through for value 3
}
case 4, 5, 6:
fmt.Println("Medium number")
default:
fmt.Println("Large number")
}
}
Type Switches
Basic Type Switches
Type switches are a special form of switch statement that allows you to switch based on the type of an interface value, enabling dynamic type checking and conversion.
package main
import "fmt"
func main() {
// Basic type switch
var value interface{} = 42
switch v := value.(type) {
case int:
fmt.Printf("Integer: %d\n", v)
case float64:
fmt.Printf("Float: %.2f\n", v)
case string:
fmt.Printf("String: %s\n", v)
case bool:
fmt.Printf("Boolean: %t\n", v)
default:
fmt.Printf("Unknown type: %T\n", v)
}
// Type switch with different values
values := []interface{}{
42,
3.14,
"hello",
true,
[]int{1, 2, 3},
map[string]int{"a": 1},
}
for i, val := range values {
fmt.Printf("Value %d: ", i+1)
switch v := val.(type) {
case int:
fmt.Printf("Integer %d\n", v)
case float64:
fmt.Printf("Float %.2f\n", v)
case string:
fmt.Printf("String '%s'\n", v)
case bool:
fmt.Printf("Boolean %t\n", v)
case []int:
fmt.Printf("Integer slice %v\n", v)
case map[string]int:
fmt.Printf("String-int map %v\n", v)
default:
fmt.Printf("Unknown type %T\n", v)
}
}
}
Type Switches with Custom Types
Type switches work with custom types and can be used to implement polymorphic behavior based on types.
package main
import "fmt"
// Custom types for demonstration
type Shape interface {
Area() float64
}
type Circle struct {
Radius float64
}
func (c Circle) Area() float64 {
return 3.14159 * c.Radius * c.Radius
}
type Rectangle struct {
Width, Height float64
}
func (r Rectangle) Area() float64 {
return r.Width * r.Height
}
type Triangle struct {
Base, Height float64
}
func (t Triangle) Area() float64 {
return 0.5 * t.Base * t.Height
}
func processShape(shape Shape) {
fmt.Printf("Processing shape: ")
switch s := shape.(type) {
case Circle:
fmt.Printf("Circle with radius %.2f, area: %.2f\n", s.Radius, s.Area())
case Rectangle:
fmt.Printf("Rectangle %.2fx%.2f, area: %.2f\n", s.Width, s.Height, s.Area())
case Triangle:
fmt.Printf("Triangle base %.2f, height %.2f, area: %.2f\n", s.Base, s.Height, s.Area())
default:
fmt.Printf("Unknown shape type: %T\n", s)
}
}
func main() {
// Create different shapes
shapes := []Shape{
Circle{Radius: 5.0},
Rectangle{Width: 4.0, Height: 6.0},
Triangle{Base: 3.0, Height: 4.0},
}
// Process each shape
for _, shape := range shapes {
processShape(shape)
}
// Type switch with interface{} values
var values []interface{} = []interface{}{
Circle{Radius: 3.0},
Rectangle{Width: 2.0, Height: 3.0},
"not a shape",
42,
}
fmt.Println("\nProcessing mixed values:")
for i, val := range values {
fmt.Printf("Value %d: ", i+1)
switch v := val.(type) {
case Shape:
fmt.Printf("Shape with area %.2f\n", v.Area())
case string:
fmt.Printf("String: %s\n", v)
case int:
fmt.Printf("Integer: %d\n", v)
default:
fmt.Printf("Unknown type: %T\n", v)
}
}
}
Type Switches with Nil Handling
Type switches can handle nil values and provide safe type checking for interface values.
package main
import "fmt"
func processValue(value interface{}) {
fmt.Printf("Processing value: %v (type: %T)\n", value, value)
switch v := value.(type) {
case nil:
fmt.Println(" Nil value received")
case int:
fmt.Printf(" Integer: %d\n", v)
if v > 0 {
fmt.Printf(" Positive integer\n")
} else if v < 0 {
fmt.Printf(" Negative integer\n")
} else {
fmt.Printf(" Zero\n")
}
case float64:
fmt.Printf(" Float: %.2f\n", v)
case string:
fmt.Printf(" String: %s (length: %d)\n", v, len(v))
case bool:
fmt.Printf(" Boolean: %t\n", v)
default:
fmt.Printf(" Unknown type: %T\n", v)
}
fmt.Println()
}
func main() {
// Test with different values including nil
testValues := []interface{}{
nil,
42,
-15,
0,
3.14159,
"hello",
"",
true,
false,
[]int{1, 2, 3},
}
fmt.Println("Testing type switches with nil handling:")
for _, value := range testValues {
processValue(value)
}
// Safe type assertion with type switch
var value interface{} = "test"
switch v := value.(type) {
case string:
fmt.Printf("Safe string conversion: %s\n", v)
case nil:
fmt.Println("Value is nil")
default:
fmt.Printf("Value is not a string: %T\n", v)
}
}
Advanced Switch Patterns
Switch with Complex Expressions
Go allows you to use complex expressions in switch statements, making them extremely flexible for various programming scenarios.
package main
import (
"fmt"
"strings"
"time"
)
func main() {
// Switch with complex expressions
currentHour := time.Now().Hour()
switch {
case currentHour >= 6 && currentHour < 12:
fmt.Println("Good morning!")
case currentHour >= 12 && currentHour < 18:
fmt.Println("Good afternoon!")
case currentHour >= 18 && currentHour < 22:
fmt.Println("Good evening!")
default:
fmt.Println("Good night!")
}
// Switch with string operations
userInput := " Hello World "
trimmed := strings.TrimSpace(userInput)
switch {
case strings.HasPrefix(trimmed, "Hello"):
fmt.Println("Greeting detected")
case strings.HasPrefix(trimmed, "Goodbye"):
fmt.Println("Farewell detected")
case strings.Contains(trimmed, "help"):
fmt.Println("Help request detected")
default:
fmt.Println("Unknown input")
}
// Switch with mathematical expressions
x, y := 10, 20
switch {
case x+y > 30:
fmt.Println("Sum is greater than 30")
case x*y > 150:
fmt.Println("Product is greater than 150")
case x > y:
fmt.Println("x is greater than y")
case x < y:
fmt.Println("x is less than y")
default:
fmt.Println("x equals y")
}
}
Switch with Function Calls
Switch statements can include function calls in both the switch expression and case values, enabling dynamic behavior.
package main
import (
"fmt"
"math"
"strings"
)
// Helper functions for switch examples
func getTemperature() int {
return 25
}
func getHumidity() int {
return 60
}
func getUserRole() string {
return "admin"
}
func calculateScore() int {
return 85
}
func main() {
// Switch with function calls
switch {
case getTemperature() > 30:
fmt.Println("Hot weather detected")
case getHumidity() > 70:
fmt.Println("High humidity detected")
default:
fmt.Println("Normal weather conditions")
}
// Switch with calculated values
switch role := getUserRole(); role {
case "admin":
fmt.Println("Administrator privileges granted")
case "moderator":
fmt.Println("Moderator privileges granted")
case "user":
fmt.Println("User privileges granted")
default:
fmt.Println("Guest privileges granted")
}
// Switch with mathematical functions
angle := 45.0
switch {
case math.Sin(angle*math.Pi/180) > 0.5:
fmt.Println("High sine value")
case math.Cos(angle*math.Pi/180) > 0.5:
fmt.Println("High cosine value")
default:
fmt.Println("Normal trigonometric values")
}
// Switch with string functions
text := "Hello World"
switch {
case strings.ToUpper(text) == text:
fmt.Println("All uppercase")
case strings.ToLower(text) == text:
fmt.Println("All lowercase")
case strings.Contains(text, " "):
fmt.Println("Contains spaces")
default:
fmt.Println("Mixed case text")
}
}
Switch with Range Conditions
Switch statements can be used with range conditions to handle numeric ranges elegantly.
package main
import "fmt"
func main() {
// Switch with range conditions
age := 25
switch {
case age >= 0 && age < 13:
fmt.Println("Child")
case age >= 13 && age < 20:
fmt.Println("Teenager")
case age >= 20 && age < 60:
fmt.Println("Adult")
case age >= 60:
fmt.Println("Senior")
default:
fmt.Println("Invalid age")
}
// Switch with score ranges
score := 85
switch {
case score >= 90:
fmt.Println("Grade: A")
case score >= 80:
fmt.Println("Grade: B")
case score >= 70:
fmt.Println("Grade: C")
case score >= 60:
fmt.Println("Grade: D")
default:
fmt.Println("Grade: F")
}
// Switch with temperature ranges
temperature := 22
switch {
case temperature < 0:
fmt.Println("Freezing")
case temperature >= 0 && temperature < 10:
fmt.Println("Cold")
case temperature >= 10 && temperature < 20:
fmt.Println("Cool")
case temperature >= 20 && temperature < 30:
fmt.Println("Warm")
case temperature >= 30:
fmt.Println("Hot")
}
}
Best Practices for Switch Statements
Choosing Between if/else and switch
package main
import "fmt"
func main() {
// When to use switch vs if/else
// Good use of switch: Multiple discrete values
day := "Monday"
// Switch is better for this case
switch day {
case "Monday":
fmt.Println("Start of work week")
case "Tuesday":
fmt.Println("Second day")
case "Wednesday":
fmt.Println("Mid-week")
case "Thursday":
fmt.Println("Almost Friday")
case "Friday":
fmt.Println("TGIF!")
default:
fmt.Println("Weekend or unknown")
}
// Good use of if/else: Complex conditions
age := 25
hasLicense := true
hasInsurance := true
// if/else is better for complex boolean logic
if age >= 18 && hasLicense && hasInsurance {
fmt.Println("Can drive legally")
} else if age >= 16 && hasLicense {
fmt.Println("Can drive with supervision")
} else if age < 16 {
fmt.Println("Too young to drive")
} else {
fmt.Println("Need license and insurance")
}
// Good use of switch: Type checking
var value interface{} = 42
switch v := value.(type) {
case int:
fmt.Printf("Integer: %d\n", v)
case string:
fmt.Printf("String: %s\n", v)
default:
fmt.Printf("Other type: %T\n", v)
}
}
Performance Considerations
package main
import "fmt"
func main() {
// Performance considerations for switch statements
// Switch is generally faster than if/else chains
// because Go can optimize switch statements better
value := 5
// Efficient switch with integer values
switch value {
case 1:
fmt.Println("One")
case 2:
fmt.Println("Two")
case 3:
fmt.Println("Three")
case 4:
fmt.Println("Four")
case 5:
fmt.Println("Five")
default:
fmt.Println("Other")
}
// Less efficient: Complex expressions in switch
// (Go has to evaluate expressions for each case)
x, y := 10, 20
switch {
case x+y > 30:
fmt.Println("Sum > 30")
case x*y > 150:
fmt.Println("Product > 150")
case x > y:
fmt.Println("x > y")
default:
fmt.Println("Default case")
}
// More efficient: Pre-calculate values
sum := x + y
product := x * y
switch {
case sum > 30:
fmt.Println("Sum > 30")
case product > 150:
fmt.Println("Product > 150")
case x > y:
fmt.Println("x > y")
default:
fmt.Println("Default case")
}
}
Code Organization and Readability
package main
import "fmt"
func main() {
// Code organization and readability best practices
// 1. Use descriptive case values
userRole := "admin"
switch userRole {
case "administrator", "admin":
fmt.Println("Full system access")
case "moderator", "mod":
fmt.Println("Content moderation access")
case "user", "member":
fmt.Println("Standard user access")
case "guest", "visitor":
fmt.Println("Limited access")
default:
fmt.Println("Unknown role - no access")
}
// 2. Group related cases together
month := "December"
switch month {
// Winter months
case "December", "January", "February":
fmt.Println("Winter season")
// Spring months
case "March", "April", "May":
fmt.Println("Spring season")
// Summer months
case "June", "July", "August":
fmt.Println("Summer season")
// Autumn months
case "September", "October", "November":
fmt.Println("Autumn season")
default:
fmt.Println("Invalid month")
}
// 3. Use default cases appropriately
status := "active"
switch status {
case "active":
fmt.Println("User is active")
case "inactive":
fmt.Println("User is inactive")
case "suspended":
fmt.Println("User is suspended")
case "banned":
fmt.Println("User is banned")
default:
fmt.Println("Unknown status - treating as inactive")
}
}
What You've Learned
Congratulations! You now have a comprehensive understanding of Go's switch statements: