把 channel 設成 nil 可以停用 select 的某個 case

nil channel 永遠 block。 這個看似沒用的性質有一個漂亮的用途:把 channel 變數設成 nil,那個 case 就等於被動態關掉了。

用途在於:channel 被 close 之後不會再 block,反而會一直回傳零值——如果不處理,那個 case 會瘋狂空轉。

for fast != nil || slow != nil {          // 兩根都關掉才離開
    select {
    case msg, ok := <-fast:
        if !ok {
            fast = nil                     // ← 停用這個 case,不再被選中
            fmt.Println("fast channel closed")
            continue
        }
        fmt.Println("received:", msg)
 
    case msg, ok := <-slow:
        if !ok {
            slow = nil
            continue
        }
        fmt.Println("received:", msg)
    }
}

三個零件合起來才成立:

  1. msg, ok := <-chokfalse 代表 channel 已被 close(跟 map 的 comma ok 是同一個語法家族)
  2. 把該變數設成 nil → nil channel 永遠 block → select 永遠不會選中它
  3. 迴圈條件用 != nil 判斷「還有沒有活著的來源」

沒有這招的話,得另外維護一組布林旗標來記錄「哪些來源結束了」,還要在每個 case 裡判斷。用 nil 直接讓 select 自己忽略它,是 Go 並行程式碼裡常見的慣用法。

相關:Channel 是 goroutine 之間的通訊管道select 是 channel 版的 switchnil map 可以讀但不能寫