Switch Statement
This is tutorial number 10 in Golang tutorial series.
What is a switch statement?
A switch is a conditional statement that evaluates an expression and compares it against a list of possible matches and executes the corresponding block of code. It can be considered as an idiomatic way of replacing complex if else
clauses.
Example
An example program is worth a hundred words. Let’s start with a simple example which will take a finger number as input and outputs the name of that finger :) . For example, 1 is thumb, 2 is index, and so on.
1package main
2
3import (
4 "fmt"
5)
6
7func main() {
8 finger := 4
9 fmt.Printf("Finger %d is ", finger)
10 switch finger {
11 case 1:
12 fmt.Println("Thumb")
13 case 2:
14 fmt.Println("Index")
15 case 3:
16 fmt.Println("Middle")
17 case 4:
18 fmt.Println("Ring")
19 case 5:
20 fmt.Println("Pinky")
21
22 }
23}
In the above program switch finger
in line no. 10, compares the value of finger
with each of the case
statements. The cases are evaluated from top to bottom and the first case which matches the expression is executed. In this case, finger
has a value of 4
and hence
Finger 4 is Ring
is printed.
Duplicate cases are not allowed
Duplicate cases with the same constant value are not allowed.
1package main
2
3import (
4 "fmt"
5)
6
7func main() {
8 finger := 4
9 fmt.Printf("Finger %d is ", finger)
10 switch finger {
11 case 1:
12 fmt.Println("Thumb")
13 case 2:
14 fmt.Println("Index")
15 case 3:
16 fmt.Println("Middle")
17 case 4:
18 fmt.Println("Ring")
19 case 4: //duplicate case
20 fmt.Println("Another Ring")
21 case 5:
22 fmt.Println("Pinky")
23
24 }
25}
Running the above program will result in the following compilation error
./prog.go:19:7: duplicate case 4 (constant of type int) in expression switch
./prog.go:17:7: previous case
Default case
We have only 5 fingers in our hands. What will happen if we input an incorrect finger number? This is where the default case comes into the picture. The default case will be executed when none of the other cases match.
1package main
2
3import (
4 "fmt"
5)
6
7func main() {
8 switch finger := 8; finger {
9 case 1:
10 fmt.Println("Thumb")
11 case 2:
12 fmt.Println("Index")
13 case 3:
14 fmt.Println("Middle")
15 case 4:
16 fmt.Println("Ring")
17 case 5:
18 fmt.Println("Pinky")
19 default: //default case
20 fmt.Println("incorrect finger number")
21 }
22}
In the above program finger
is 8
and it does not match any of the cases and hence incorrect finger number
in the default case is printed. It’s not necessary that default
should be the last case in a switch statement. It can be present anywhere in the switch.
You might also have noticed a small change in the declaration of finger
. It is declared in the switch itself. A switch can include an optional statement that is executed before the expression is evaluated. In line no. 8, finger
is first declared and then used in the expression. The scope of finger
in this case is limited to the switch block.
Multiple expressions in case
It is possible to include multiple expressions in a case by separating them with comma.
1package main
2
3import (
4 "fmt"
5)
6
7func main() {
8 letter := "i"
9 switch letter {
10 case "a", "e", "i", "o", "u": //multiple expressions in case
11 fmt.Printf("%s is a vowel", letter)
12 default:
13 fmt.Printf("%s is not a vowel", letter)
14 }
15}
The above program finds whether letter
is a vowel or not. The code case "a", "e", "i", "o", "u":
in line no. 10 matches any of the vowels. Since i
is a vowel, this program prints
i is a vowel
Expressionless switch
The expression in a switch is optional and it can be omitted. If the expression is omitted, the switch is considered to be switch true
and each of the case
expression is evaluated for truth and the corresponding block of code is executed.
1package main
2
3import (
4 "fmt"
5)
6
7func main() {
8 hour := 15 // hour in 24 hour format
9 // Using switch to determine the work shift
10 switch {
11 case hour >= 6 && hour < 12:
12 fmt.Println("It's the morning shift.")
13 case hour >= 12 && hour < 17:
14 fmt.Println("It's the afternoon shift.")
15 case hour >= 17 && hour < 21:
16 fmt.Println("It's the evening shift.")
17 case (hour >= 21 && hour <= 24) || (hour >= 0 && hour < 6):
18 fmt.Println("It's the night shift.")
19 default:
20 fmt.Println("Invalid hour.")
21 }
22}
In the above program, the expression is absent in switch and hence it is considered as true and each of the cases is evaluated. hour >= 12 && hour < 17
in line no. 13 is true
and the program prints
It's the afternoon shift.
This type of switch can be considered as an alternative to multiple if else
clauses.
Fallthrough
In Go, the control comes out of the switch statement immediately after a case is executed. A fallthrough
statement is used to transfer control to the first statement of the case that is present immediately after the case which has been executed.
Let’s write a program to understand fallthrough. Our program will check whether the input number is less than 50, 100, or 200. For instance, if we input 75, the program will print that 75 is less than both 100 and 200. We will achieve this using fallthrough
.
1package main
2
3import (
4 "fmt"
5)
6
7func number() int {
8 num := 15 * 5
9 return num
10}
11
12func main() {
13 switch num := number(); { //num is not a constant
14 case num < 50:
15 fmt.Printf("%d is lesser than 50\n", num)
16 fallthrough
17 case num < 100:
18 fmt.Printf("%d is lesser than 100\n", num)
19 fallthrough
20 case num < 200:
21 fmt.Printf("%d is lesser than 200", num)
22 }
23}
Switch and case expressions need not be only constants. They can be evaluated at runtime too. In the program above num
is initialized to the return value of the function number()
in line no. 13. The control comes inside the switch and the cases are evaluated. case num < 100:
in line no. 17 is true and the program prints 75 is lesser than 100
. The next statement is fallthrough
. When fallthrough
is encountered the control moves to the first statement of the next case and also prints 75 is lesser than 200
. The output of the program is
75 is lesser than 100
75 is lesser than 200
fallthrough
should be the last statement in a case
. If it is present somewhere in the middle, the compiler will complain that fallthrough statement out of place
.
Fallthrough happens even when the case evaluates to false
There is a subtlety to be considered when using fallthrough
. Fallthrough will happen even when the case evaluates to false.
Please consider the following program.
1package main
2
3import (
4 "fmt"
5)
6
7func main() {
8 switch num := 25; {
9 case num < 50:
10 fmt.Printf("%d is lesser than 50\n", num)
11 fallthrough
12 case num > 100:
13 fmt.Printf("%d is greater than 100\n", num)
14 }
15
16}
In the above program, num
is 25 which is less than 50 and hence the case in line no. 9 evaluates to true
. A fallthrough
is present in line no. 11. The next case case num > 100:
in line no. 12 is false since num < 100. But fallthrough doesn’t consider this. Fallthrough will happen even though the case evaluates to false
.
The program above will print
25 is lesser than 50
25 is greater than 100
So be sure that you understand what you are doing when using fallthrough.
One more thing is fallthrough
cannot be used in the last case of a switch since there are no more cases to fallthrough. If fallthrough
is present in the last case, it will result in the following compilation error cannot fallthrough final case in switch
Breaking switch
The break
statement can be used to terminate a switch early before it completes. Let’s just modify the above example to a contrived one to understand how break works.
Let’s add a condition that if num
is less than 0 then the switch should terminate.
1package main
2
3import (
4 "fmt"
5)
6
7func main() {
8 switch num := -5; {
9 case num < 50:
10 if num < 0 {
11 break
12 }
13 fmt.Printf("%d is lesser than 50\n", num)
14 fallthrough
15 case num < 100:
16 fmt.Printf("%d is lesser than 100\n", num)
17 fallthrough
18 case num < 200:
19 fmt.Printf("%d is lesser than 200", num)
20 }
21
22}
In the above program num
is -5
. When the control reaches the if statement in line no. 10, the condition is satisfied since num < 0
. The break statement terminates the switch before it completes and the program doesn’t print anything :).
Breaking the outer for loop
When the switch case is inside a for loop, there might be a need to terminate the for loop early. This can be done by labeling the for loop and breaking the for loop using that label inside the switch statement. Let’s look at an example.
Let’s write a program to generate a random even number.
We will create an infinite for loop and use a switch case to determine whether the generated random number is even. If it is even, the generated number is printed and the for loop is terminated using its label. The Intn
function of the rand
package is used to generate non-negative pseudo-random numbers.
1package main
2
3import (
4 "fmt"
5 "math/rand"
6)
7
8func main() {
9randloop:
10 for {
11 switch i := rand.Intn(100); {
12 case i%2 == 0:
13 fmt.Printf("Generated even number %d", i)
14 break randloop
15 }
16 }
17
18}
In the program above, the for loop is labeled randloop
in line no. 9. A random number is generated between 0 and 99 (100 is not included) using the Intn
function in line no. 11. If the generated number is even, the loop is broken in line no. 14 using the label.
This program prints,
Generated even number 18
Please note that if the break statement is used without the label, the switch statement will only be broken and the loop will continue running. So labeling the loop and using it in the break statement inside the switch is necessary to break the outer for loop.
This brings us to the end of this tutorial. There is one more type of switch called type switch. We will look into this when we learn about interfaces.
Please share your valuable comments and feedback. Please consider sharing this tutorial tutorial on twitter or LinkedIn. Have a good day.
Next tutorial - Arrays and Slices