select case 最终会被编译器,编译成
select {
case v, ok = <-c:
... foo
default:
... bar
}
as
if c != nil && selectnbrecv2(&v, &ok, c) {
... foo
} else {
... bar
}
select {
case v = <-c:
... foo
default:
... bar
}
as
if selectnbrecv(&v, c) {
... foo
} else {
... bar
}
select {
case c <- v:
... foo
default:
... bar
}
as
if selectnbsend(c, v) {
... foo
} else {
... bar
}
我们在使用select 有以上三种情况,编译器会做对应的转化,上面的这三个selectnbsend、selectnbrecv、selectnbrecv2 函数最终都分别调用runtime.chansend、runtime.chanrecv 对于channel的操作 select是不可缺少的一部分,但是需要注意的是,select并不像switch那样case顺序执行的,例如下面的代码: “因为select 的case 是伪随机的,所以才会引发异常”。
func main() {
runtime.GOMAXPROCS(1)
int_chan := make(chan int, 1)
string_chan := make(chan string, 1)
int_chan <- 1
string_chan <- "Golang我们走,我们要做好朋友!!!"
for {
select {
case value := <-int_chan:
fmt.Println(value)
case value := <-string_chan:
panic(value) //总会随机到我,我会执行的。。。
}
}
}
这里需要注意下虽然case被随机了,但是所有case关键字右侧的发送或者接受语句中的表达式和元素表达式都要被先求值,求值的顺序分别是自上而下,从左到右的顺序。
在源码中每一个select 对应一个hselect结构 每个hselect 结构下面都有个scase的数组记录每个case, 在scase中记录着c hchan的结构也就是专栏的上一篇文章channel的结构 pollorder 将元素从新排列,scase就被乱序了。
func main() {
runtime.GOMAXPROCS(1)
int_chan := make(chan int, 1)
select {
default:
fmt.Println("default...")
case value := <-int_chan:
fmt.Println(value)
}
}
最后还要说明一下,select里面的default 和case的位置摆放顺序,不会影响分支选择的规则。
有疑问加站长微信联系(非本文作者)