這是一個建立於 的文章,其中的資訊可能已經有所發展或是發生改變。
select case 最終會被編譯器,編譯成
select { case v, ok = <-c: ... foo default: ... bar} asif c != nil && selectnbrecv2(&v, &ok, c) { ... foo } else { ... bar}
select { case v = <-c: ... foo default: ... bar} asif selectnbrecv(&v, c) { ... foo } else { ... bar}
select { case c <- v: ... foo default: ... bar } asif 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 <- 1string_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的位置擺放順序,不會影響分支選擇的規則。