select语句是专门为通道设计的,它可以包含若干个候选分支,每个分支中的case表达式都会包含针对摸个通道的发送活接收操作。
基础语法
select {
case <-chan1:
// 接收操作,如果成功从chan1读到数据,则进行该case处理语句
case ret, open := <-chan2:
// 接收操作,如果成功从chan2读到数据,则进行该case处理语句
// ret: 从chan2读到的值,通道关闭时,ret为该类型的零值
// open: 用来判断chan2是否关闭。关闭通道使用close(retCh)
case chan3 <- 1:
// 发送操作,如果成功向chan3写入数据,则进行该case处理语句
case <-time.After(time.Second * 1):
// 1秒后超时,存在default时,永远不会超时
default:
// 如果所有case语句都未执行,则进行default处理语句
}
分支选择规则
对于每一个case表达式,都至少会包含一个发送操作或一个接收操作,同时也可能会包含其他表达式。
- 如果case表达式是包含了接收表达式的短变量声明时,那么在赋值符号左侧的就可以是一个或者两个表达式(表达式的结果必须是可被赋值的)。
- 上述case表达式被求值时,它包含的多个表达式总会以从左到右的顺序被求值。
在select语句开始执行时,所有候选分支中的case表达式都会在先被求值,且求值的顺序是依从代码编写的顺序从上到下的。
即,排在最上边的候选分支中最左边的表达式会最先被求职,然后是它右边的表达式,仅当最上边的候选分支中的所有表达式都被求值完毕后,上数第二个候选分支中的表达式才会被求值,顺序同样是从左到右,以此类推。
仅当select语句中的所有case表达式都被求值完毕后,它才会开始选择候选分支。
- 满足条件时执行分支。所有候选分支都不满足条件时,执行默认分支。若默认分支不存在,则select语句所在goroutine被阻塞,直到某一候选分支的条件被满足。
- 一个select中只能有一个默认分支。默认分支只有在所有候选分支的条件都不满足时被执行,这与它的编写位置无关。
- select语句的每次执行、case表达式求值以及分支选择都是独立的。
- select是否并发安全取决于case表达式和分支中的代码是否并发安全。