Go 的 select
语句可以选中多个已知的 channel 变量。但是假如你要 select
的 channel 并不是固定的,比如放在一个 slice 中,那么你需要用 reflect.Select
函数来实现。
这个函数不难理解。这里有一个简单的代码例子:
package main
import (
"fmt"
"reflect"
"time"
)
func main() {
var cases []reflect.SelectCase
var chs []chan int
for i := 0; i < 4; i++ {
chs = append(chs, make(chan int, 10))
cases = append(cases, reflect.SelectCase{
Dir: reflect.SelectRecv,
Chan: reflect.ValueOf(chs[i]),
})
}
go func() {
n := 0
for {
for i := 0; i < 4; i++ {
chs[i] <- n
n++
time.Sleep(1 * time.Second)
}
}
}()
for {
i, v, ok := reflect.Select(cases)
fmt.Printf("Chan %d: received %d, %t\n", i, v.Int(), ok)
}
}
需要注意的是,如果 cases
中有 closed 的 recv channel,reflect.Select()
会马上返回,其中 v
为该 channel 的数据类型的零值(比如 chan int
对应的是 0),ok
为 false。
还没有实验 send 数据到一个 closed channel 会有什么表现。