Mọi thao tác gửi hoặc nhận trên channel nil đều chặn vĩnh viễn — không panic, không lỗi, chỉ đứng im. Đây là hành vi được định nghĩa trong spec chứ không phải bug.
Hệ quả trong select: nhánh có channel nil không bao giờ được chọn. Người ta dùng đúng tính chất đó để tắt một nhánh khi nó đã hết việc.
Tình huống điển hình: gộp hai channel, một cái đóng trước. Channel đã đóng luôn sẵn sàng trả zero value, nên nếu cứ để nguyên thì select sẽ quay vòng liên tục ăn CPU. Gán nó về nil là loại nó khỏi vòng chọn.
go
func merge(a, b <-chan int) <-chan int {
out := make(chan int)
go func() {
defer close(out)
for a != nil || b != nil {
select {
case v, ok := <-a:
if !ok {
a = nil // disable this case, stop spinning on a closed channel
continue
}
out <- v
case v, ok := <-b:
if !ok {
b = nil
continue
}
out <- v
}
}
}()
return out
}Mặt trái: một channel nil do quên khởi tạo (var ch chan int mà không make) sẽ làm goroutine treo im lặng — đây là nguồn goroutine leak khó tìm, vì không có thông báo lỗi nào.