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}

Run in playground

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}

Run in playground

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}

Run in playground

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}

Run in playground

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}

Run in playground

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}

Run in playground

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}

Run in playground

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}

Run in playground

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}

Run in playground

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