Go语言中switch和select有什么区别?

68
除了一个函数需要参数,另一个不需要,Go语言中的switchselect有什么区别吗?
3个回答

94

select 只用于通道。示例

switch 用于具体类型。示例

select 将随机选择多个有效选项,而 switch 将按顺序进行(并需要使用 fallthrough 来匹配多个选项)。

请注意,当与关键字 .(type) 一起使用时,switch 还可以遍历接口类型。

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."

11
如果您能对“switch”语句的解释进行扩展,那会很好。它不仅限于具体类型。默认情况下,它执行相等性检查,并且在没有参数的情况下,每个case语句必须是布尔表达式,选择第一个为真的case语句。 - Endophage

44

switch 语句基于变量值(任意类型)做出决策。阅读 此文档 以获取更多细节:

Go 的 switch 功能比 C 更为通用。表达式不必是常量或整数,case 会从上到下逐一进行评估直到找到匹配项,如果 switch 没有表达式则默认为 true。因此,使用 switch 可以编写 if-else-if-else 链,这是惯用方法。

示例用法:(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)
    }
}

select语句允许一个goroutine等待多个通信操作。

当其中一个case可以运行时,select会阻塞,然后执行该case。如果有多个case准备好了,则会随机选择一个。以下是一个例子:(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)
        }
    }
}

这段代码是一个有趣的笑话 ⏰ - undefined

8

选择语句

“select”语句用于选择一组可能的发送或接收操作中的哪一个将继续执行。它看起来类似于“switch”语句,但所有情况都涉及通信操作。

开关语句

“switch”语句提供多路执行。表达式或类型说明符与“switch”内部的“case”进行比较,以确定要执行的分支。有两种形式:表达式开关和类型开关。在表达式开关中,情况包含与开关表达式的值进行比较的表达式。在类型开关中,情况包含与特殊注释的开关表达式的类型进行比较的类型。在switch语句中,switch表达式仅计算一次。

是的,有很多不同之处:

  • select只适用于通道事件(接收、关闭或等待),但您可以使用switch仅用于比较通道数据,例如case <-ch == 1:
  • switch以确定性方式工作,就像多个ifif else语句一样,但是select以非确定性方式选择case:您无法说哪个情况在select中首先运行
  • 您不能在select中使用fallthrough
  • switch中,将表达式或类型说明符与switch内部的cases进行比较,以确定要执行的分支。
  • switch本身不会阻塞,但是select会阻塞底层goroutine,除非您使用default
  • switch有两种形式:表达式开关和类型开关
  • 在阻塞的select(没有default)中,没有CPU使用率(goroutine睡眠)
  • select不同,您不能在switch中使用case <-ch:

工作示例代码:

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)
    }
}

输出:

switch1
switch2
select2 d= 2

另一次运行的输出:

switch1
switch2
select1 d= 2

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接