switch os := runtime.GOOS; os {
case "darwin":
	fmt.Println("OS X.")
case "linux":
	fmt.Println("Linux.")
default:
	// freebsd, openbsd,
	// plan9, windows...
	fmt.Printf("%s.\n", os)
}

Checks for equality.

Another example that showcases more features:

words := []string{"a", "cow", "smile", "gopher",
    "octopus", "anthropologist"}
for _, word := range words {
    switch size := len(word); size { // uses parentheses here, but not for each case block
    case 1, 2, 3, 4: // separate by comma
        fmt.Println(word, "is a short word!")
    case 5:
        wordLen := len(word) // scoped to case block
        fmt.Println(word, "is exactly the right length:", wordLen)
    case 6, 7, 8, 9: // nothing will happen in these cases
    default:
        fmt.Println(word, "is a long word!")
    }
}
// a is a short word!
// cow is a short word!
// smile is exactly the right length: 5
// anthropologist is a long word!

Go only runs the selected case, not all the cases that follow. So the break keyword isn’t needed like in other languages.

fallthrough keyword can be specified so that the case continue to the next one, but it’s generally a sign that you may should restructure your code.

break keyword

break keyword can be added to exit early from the switch, but it’s also a bad sign.

When you want to break a loop early with a switch inside, with this code Go will break switch statement instead:

func main() {
    for i := 0; i < 10; i++ {
        switch i {
        case 0, 2, 4, 6:
            fmt.Println(i, "is even")
        case 3:
            fmt.Println(i, "is divisible by 3 but not 2")
        case 7:
            fmt.Println("exit the loop!")
            break
        default:
            fmt.Println(i, "is boring")
        }
    }
}

To fix it use break with label:

break loop

Blank switch

While regular switch only allow to check for equality, when you omit the value you compare against, you can any boolean comparison.

words := []string{"hi", "salutations", "hello"}
for _, word := range words {
    switch wordLen := len(word); {
    case wordLen < 5:
        fmt.Println(word, "is a short word!")
    case wordLen > 10:
        fmt.Println(word, "is a long word!")
    default:
        fmt.Println(word, "is exactly the right length.")
    }
}
// Output:
// hi is a short word!
// salutations is a long word!
// hello is exactly the right length.

Use blank switch to replace a series of if/else statements when you have multiple related cases. FizzBuzz example:

// if-else
for i := 1; i <= 100; i++ {
	if i%3 == 0 && i%5 == 0 {
		fmt.Println("FizzBuzz")
		continue
	}
	if i%3 == 0 {
		fmt.Println("Fizz")
		continue
	}
	if i%5 == 0 {
		fmt.Println("Buzz")
		continue
	}
	fmt.Println(i)
}
 
// blank switch
for i := 1; i <= 100; i++ {
    switch {
    case i%3 == 0 && i%5 == 0:
        fmt.Println("FizzBuzz")
    case i%3 == 0:
        fmt.Println("Fizz")
    case i%5 == 0:
        fmt.Println("Buzz")
    default:
        fmt.Println(i)
    }
}

q What does that mean?

Go’s switch cases need not be constants, and the values involved need not be integers. https://go.dev/tour/flowcontrol/9

switch can be used without a condition.

This construct can be a clean way to write long if-then-else chains.

package main
 
import (
	"fmt"
	"time"
)
 
func main() {
	t := time.Now()
	switch {
	case t.Hour() < 12:
		fmt.Println("Good morning!")
	case t.Hour() < 17:
		fmt.Println("Good afternoon.")
	default:
		fmt.Println("Good evening.")
	}
}

q Why though?