What is the difference between switch and select in Go?

Is there any difference between switch and select in Go,
apart from the fact that one takes an argument and the other not?


A select is only used with channels. Example

A switch is used with concrete types. Example

A select will choose multiple valid options at random, while aswitch will go in sequence (and would require a fallthrough to match multiple.)

Note that a switch can also go over types for interfaces when used with the keyword .(type)

var a interface{}
a = 5
switch a.(type) {
case int:
     fmt.Println("an int.")
case int32:
     fmt.Println("an int32.")
}
// in this case it will print "an int."

switch is used to make a decision based on a variable value of any type. Read this for more details:

Go's switch is more general than C's. The expressions need not be constants or even integers, the cases are evaluated top to bottom until a match is found, and if the switch has no expression it switches on true. It's therefore possible—and idiomatic—to write an if-else-if-else chain as a switch.

Sample Use: (Go Playground)

package main

import (
    "fmt"
    "runtime"
)

func main() {
    fmt.Print("Go runs on ")
    switch os := runtime.GOOS; os {
    case "darwin":
        fmt.Println("OS X.")
    case "linux":
        fmt.Println("Linux.")
    default:
        // freebsd, openbsd,
        // plan9, windows...
        fmt.Printf("%s.", os)
    }
}

The select statement lets a goroutine wait on multiple communication operations.

A select blocks until one of its cases can run, then it executes that case. It chooses one at random if multiple are ready. Here is one example: (Go Playground)

package main

import (
    "fmt"
    "time"
)

func main() {
    tick := time.Tick(100 * time.Millisecond)
    boom := time.After(500 * time.Millisecond)
    for {
        select {
        case <-tick:
            fmt.Println("tick.")
        case <-boom:
            fmt.Println("BOOM!")
            return
        default:
            fmt.Println("    .")
            time.Sleep(50 * time.Millisecond)
        }
    }
}

Select statements

A "select" statement chooses which of a set of possible send or receive operations will proceed. It looks similar to a "switch" statement but with the cases all referring to communication operations.

Switch statements

"Switch" statements provide multi-way execution. An expression or type specifier is compared to the "cases" inside the "switch" to determine which branch to execute. There are two forms: expression switches and type switches. In an expression switch, the cases contain expressions that are compared against the value of the switch expression. In a type switch, the cases contain types that are compared against the type of a specially annotated switch expression. The switch expression is evaluated exactly once in a switch statement.

Yes, there are many differences:

  • select works just on channel events (receive, close or wait), but you can use switch just for comparing channel data like case <-ch == 1:
  • switch works in deterministic way like multiple if or if else statement, but select chooses the case in non-deterministic way: you can't say which case runs first in select
  • you can't use fallthrough in select
  • in switch An expression or type specifier is compared to the cases inside the switch to determine which branch to execute.
  • switch is not blocking itself, but select is blocking underlying goroutine unless you use default
  • switch has two forms: expression switches and type switches
  • in blocking select (without default) there is no CPU usage (goroutine sleep)
  • Unlike select you can't use case <-ch: inside switch.

Working sample Code:

package main

import "fmt"

func main() {
    ch := make(chan int, 4)
    ch <- 1
    ch <- 2
    ch <- 3
    ch <- 4
    close(ch)
    switch {
    //case <-ch: //  invalid case <-ch in switch (mismatched types int and bool)
    case <-ch == 1:
        fmt.Println("switch1")
        fallthrough
    case <-ch == 2:
        fmt.Println("switch2")
    }
    select {
    case d := <-ch:
        fmt.Println("select1 d=", d)
    case d := <-ch:
        fmt.Println("select2 d=", d)
    }
}

output:

switch1
switch2
select2 d= 2

output of another run:

switch1
switch2
select1 d= 2