select 会 block 到指定的一批 channel ready;如果多个 channel ready,会随机选择其中一个。写法很像 switch:
select {
// 可以是 receive from channel
case s := <-output:
fmt.Println(s1)
// 也可以是 send to channel
case c <- "hello":
// do nothing
case <-done:
fmt.Println("Done")
}可以有 default 分支。效果是如果没有 channel ready,就会走 default:
default:
fmt.Println("None of the other case is ready")Patterns
select 可以用来表示这一种场景:把一个消息发送到某一 channel;如果无法发送(比如 channel 缓冲区满),则无视。
select {
case c.errors <- err:
default:
// if c.errors is full, do nothing
}select 经常跟 for 配合,用来实现超时或者退出功能。
实现超时功能(来自 这里):
func main() {
c := boring("Joe")
for {
select {
case s := <-c:
fmt.Println(s)
case <-time.After(1 * time.Second):
fmt.Println("You're too slow.")
return
}
}
}注意上面的 time.After(1 * time.Second) 是在每次执行 select 语句时都会 evaluate 的,意味着 for 循环中的每次 select 都会有 1s 超时时间。如果你想设置整个 for 循环的超时时间,这样写:
func main() {
c := boring("Joe")
timeout := time.After(5 * time.Second)
for {
select {
case s := <-c:
fmt.Println(s)
case <-timeout:
fmt.Println("You talk too much.")
return
}
}
}读数据,当读完时执行清理工作(并不实用):
readResult:
for {
select {
case s <- result:
fmt.Println(s)
case <-done:
cleanUp()
break readResult
}
}因为 break 默认退出的是最内层的 for / switch / select 语句,因此想 break 掉 for 循环时,需要配合 label(readResult:)使用。