Go

Why is a nil channel useful in a select? Show an example.

Question 192HardGo 1.22 to 1.25

Send and receive on a nil channel block forever, so a select case on a nil channel is never chosen. Setting a channel variable to nil therefore switches that case off at runtime. That's the standard way to merge channels that close at different times, or to turn sending on only when you have something to send.

func mergeTwo(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; continue }
				out <- v
			case v, ok := <-b:
				if !ok { b = nil; continue }
				out <- v
			}
		}
	}()
	return out
}

Without setting it to nil, a closed channel is always ready and returns zero values, so the loop would spin at 100% CPU. Another use is the conditional send:

var sendCh chan<- Item // nil until we have something
var next Item
if len(queue) > 0 {
	sendCh = out
	next = queue[0]
}
select {
case sendCh <- next: queue = queue[1:]
case it := <-in:     queue = append(queue, it)
}

Trap: writing case sendCh <- queue[0]: directly looks fine but panics with "index out of range" when the queue is empty. select evaluates every send value on entry, even for a case whose channel is nil, so the value has to be computed safely beforehand.

More on Channels & select

All 38 Channels & select questions