The switch statement is seldom used in most applications, but appears in almost all programming languages. I believe this is because switchis only useful in a very specific case. Thankfully, Go took a step back and said “we don’t have to do it the way everyone is used to” and rethought what it means to handle lots of branches of the same decision point without resulting to a chain of ifstatements.

The “break” Killed the “switch”

Consider the simplest and most obvious use of a switch in C++. Most languages that implement switchwill use a similar syntax:

int dayOfTheWeek = 3;

char *dayName = null; switch (dayOfTheWeek) {

case 1:

dayName = "Monday";

break;

case 2:

dayName = "Tuesday";

break;

case 3:

dayName = "Wednesday";

break;

case 4:

dayName = "Thursday";

break;

case 5:

dayName = "Friday";

break;

case 6:

dayName = "Saturday";

break;

case 7:

dayName = "Sunday";

break;

}

I realise this could be reduced to an array; just pretend these are more random values if you wish. This is already long and cumbersome, however it is slightly neater but longer than the alternative with chained if else statements:

int dayOfTheWeek = 3;

char *dayName = null; if (dayOfTheWeek == 1) {

dayName = "Monday";

} else if (dayOfTheWeek == 2) {

dayName = "Tuesday";

} else if (dayOfTheWeek == 3) {

dayName = "Wednesday";

} else if (dayOfTheWeek == 4) {

dayName = "Thursday";

} else if (dayOfTheWeek == 5) {

dayName = "Friday";

} else if (dayOfTheWeek == 6) {

dayName = "Saturday";

} else if (dayOfTheWeek == 7) {

dayName = "Sunday";

}

To me this is very ugly, repeats a lot of code and is less explicit than the switch version, but since it’s shorter and more flexible it’s usually the preferred option. Now let’s see how Go handles it:

dayOfTheWeek := 3

var dayName string switch dayOfTheWeek {

case 1:

dayName = "Monday"

case 2:

dayName = "Tuesday"

case 3:

dayName = "Wednesday"

case 4:

dayName = "Thursday"

case 5:

dayName = "Friday"

case 6:

dayName = "Saturday"

case 7:

dayName = "Sunday"

}

Yes! Now we get to the crux of it. The breakstatement is the wart that has killed the beautiful simplicity of the switch. It should have been original designed with the intention that in the vast majority of cases you will only want one case to match and not have to pollute your source with breakstatements.

Collapsing Cases

Since the normal implementation relies on the breakto not fall through; several cases can grouped. Go takes it one step further by comma separating all the matching values. This is less typing and even more explicit:

dayOfTheWeek := 3

var dayName string switch dayOfTheWeek {

case 1, 2, 3, 4, 5:

dayName = "Weekday"

case 6, 7:

dayName = "Weekend"

}

Expressions

The other reason why switchis seldom used is because in many languages the value that it’s switching on must by a primitive, sometimes even restricted to an integer. Go removed this limitation as well by allowing complete expressions for cases:

switch {

case dayOfTheWeek <= 5:

dayName = "Weekday"

case dayOfTheWeek > 5:

dayName = "Weekend"

}

If you use expressions for cases you do not need to even specify a switch value. This works more like a chained ifstatement. Furthermore, Go’s ability to declare scoped variables makes this switch even more readable:

dayOfTheWeek := 3

var dayName string switch friday := 5; true {

case dayOfTheWeek <= friday:

dayName = "Weekday"

case dayOfTheWeek > friday:

dayName = "Weekend"

}

Empty Cases

Empty cases mean it does nothing:

switch hasHadCoffee {

case false:

// Don't talk to me.

case true:

readyToTalk()

}

Falling Through

If traditional switches rely on break statements to not fall through, then fallthrough would be the opposite. A casenever falls through unless you have an explicit fallthrough:

count := 0 switch {

default:

count++

fallthrough

case false:

count++

}

It’s important to recognise that countis 2 because fallthroughwill always run the next case, even if it wouldn’t normally be hit.

Type Switching

One great thing about Go is that type casting and assertions can be put into the same line:

var value interface{} = "hello"

if str, ok := value.(string); ok {

// str must be a string

} else {

// error handling

}

If there are more than one possible expected type you can do the same thing with a switch:

var value interface{} = "hello"

switch o := value.(type) {

case string:

// o is a string

case int:

// o is an int

default:

// Handle the unknown type

panic(o)

}

Conclusion