Often in Go a selection must be made based on the value of a variable. For an input, a special value must be returned. A switch
handles this.
In Go we have versatile switch
statements. We can match a variable to a constant value (even in a list). Or we can match based on expressions and logic.
To start, we use a switch
with 3 cases. Each case matches an expression. So if height is less than or equal to 4, the first case is reached.
package main import "fmt" func main() { height := 5 // Use switch on the height variable. switch { case height <= 4: fmt.Println("Short") case height <= 5: fmt.Println("Normal") case height > 5: fmt.Println("Tall") } }Normal
This is another form of the switch
construct. We specify a variable after the switch
keyword. Then we use constants or lists of constants to match the variable.
switch
case 10 is matched and the string
"Even" is printed with fmt
.package main import "fmt" func main() { id := 10 // Use switch with multiple values in each case. switch id { case 10, 12, 14: fmt.Println("Even") case 11, 13, 15: fmt.Println("Odd") } }Even
This is a common code pattern: we use a switch
to return a value in a func
. We use return statements within the cases.
switch
. If nothing matches, the final return is reached.package main import "fmt" func result(v int) int { // Return a value based on a switch. switch v { case 10, 20, 30: return v + 5 case 15, 25, 35: return v - 5 } return v } func main() { // Call the method that uses a switch. number := result(10) fmt.Println(number) number = result(25) fmt.Println(number) }15 20
This keyword can be used in a case in a switch
statement. When fallthrough is encountered, the next case is entered (even if the expression does not match).
Test()
is called with the value of 0. The case 0 is reached in test()
, and the func
is done.test()
method is called next with a value of 1. Case 1 is reached, and then case 0 is entered because control "falls through."package main import "fmt" func test(value int) { switch value { case 1: // For 1, handle as 1 and fall-through to 0. fmt.Println("One") fallthrough case 0: // For 0, just print zero. fmt.Println("Zero") break } } func main() { fmt.Println(0) test(0) fmt.Println(1) test(1) }0 Zero 1 One Zero
A switch
's cases must be unique. Every constant, even in lists, is checked against the entire switch
. A "duplicate case" error may be reported.
package main import "fmt" func main() { value := 10 // Duplicate cases are not allowed. switch value { case 10: fmt.Println(true) case 10: fmt.Println(true) } }C:\programs\file.go:14: duplicate case 10 in switch previous case at C:\programs\file.go:12
In some languages a float
cannot be used in a switch
. But in Go we can switch
on floating-point numbers. This program shows a switch
on a variable with value 2.5.
package main import "fmt" func main() { value := 2.5 // Switch on a floating-point value. switch value { case 1.5: fmt.Println("One point five") case 2.5: fmt.Println("Two point five") } }Two point five
A switch
can have a default case. This is reached when no other case matches. A switch
can have 0 or 1 default cases, and the position in the switch
statement is not important.
package main import "fmt" func main() { value := 5 // Switch on the value. switch value { case 4: fmt.Println("FOUR") default: // The default case is reached. fmt.Println("UNKNOWN") } }UNKNOWN
String
switch
The Go language supports switch
on strings. We can specify string
literals in the case statements. The strings must exactly match.
package main import "fmt" func main() { animal := "cat" // Switch on string. switch animal { case "bird": fmt.Println("MATCHED BIRD") case "cat": fmt.Println("MATCHED CAT") } }MATCHED CAT
switch
Does the switch
statement provide a huge performance boost over if? I tested a simple integer switch
against an equivalent if-else
chain.
switch
statement. The cases in the switch
are all encountered.if
-statement instead of switch
. The if
-statements do the same thing as the switch
.switch
statement. On numbers, prefer switch
when possible.package main import ( "fmt" "time" ) func main() { Version1() Version2() } func Version1() { result := 0 t0 := time.Now() // Version 1: test switch statement. for i := 0; i < 10000000; i++ { for v := 0; v < 5; v++ { switch v { case 0: result += 1 case 1, 2, 3: result += 2 case 4: result += 3 } } } t1 := time.Now() // Results. fmt.Println(result) fmt.Println(t1.Sub(t0)) } func Version2() { result := 0 t0 := time.Now() // Version 2: test if-statement. for i := 0; i < 10000000; i++ { for v := 0; v < 5; v++ { if v == 0 { result += 1 } else if v == 1 || v == 2 || v == 3 { result += 2 } else if v == 4 { result += 3 } } } t1 := time.Now() // Results. fmt.Println(result) fmt.Println(t1.Sub(t0)) }100000000 53.8862ms Switch 100000000 82.807ms If
switch
With a type switch
we can detect what interfaces a variable implements. We use the (type) syntax to get the type and pass it to the switch
. Then we have interface
cases.
switch
on an interface
{} variable in the test()
method. We then use (type).package main import "fmt" type Page interface { PrintPage() } type HtmlPage struct { // Implement Page interface. Page } type Image interface { PrintImage() } type ImagePage struct { // Implement Image interface. Image } func test(value interface{}) { // Use type switch to test interface type. // ... The argument is an interface. switch value.(type) { case nil: fmt.Println("Is nil interface") case Page: fmt.Println("Is page interface"); case Image: fmt.Println("Is image interface"); } } func main() { // Create class that implements interface and pass to test func. item1 := new(HtmlPage) test(item1) item2 := new(ImagePage) test(item2) }Is page interface Is image interface
It is possible to use a lookup table in certain Go programs to improve performance over a switch
. This can help hot loops.
Switches are emphasized in Go. We use them preferentially over if
-statements. And most ifs can be rewritten elegantly with switch
.