Lesson 5 / 25

Closing Channels, Ranging and nil Channels

Who closes, what receivers see, and the three special cases.

The rules of close

close(ch) means no more values will be sent. After close, receivers first drain any buffered values, then every receive returns immediately with the zero value; the two-value form v, ok := <-ch reports ok == false once the channel is closed and empty. for v := range ch loops until that happens. Sending on a closed channel panics, closing a closed channel panics, and closing a nil channel panics. Hence the rule: only the sender closes, and when there are several senders, a coordinator closes the channel after all of them are done (typically after wg.Wait()). Closing is optional; it is a signal, not a resource cleanup, so close only when receivers need to know the stream has ended. A nil channel (the zero value of a channel variable) blocks forever on both send and receive, which is a bug in ordinary code but a useful tool inside select.

Many senders, one closer

The coordinator closes after every sender has finished.

package main

import (
	"fmt"
	"sync"
)

func main() {
	results := make(chan int)
	var wg sync.WaitGroup

	for i := 1; i <= 3; i++ {
		wg.Add(1)
		go func() {
			defer wg.Done()
			results <- i * i // Go 1.22+: each iteration has its own i
		}()
	}

	// Close only after all senders are done, in its own goroutine
	// so that main can start receiving straight away.
	go func() {
		wg.Wait()
		close(results)
	}()

	for r := range results { // ends when results is closed and drained
		fmt.Println(r)
	}

	v, ok := <-results
	fmt.Println(v, ok) // 0 false: closed channels yield the zero value
}

Use chan struct{} for pure signals

A chan struct{} carries no data, so close(done) is a clean broadcast: every goroutine waiting on <-done wakes up at once, and later receivers return immediately too.

Quick check: What does a receive from a closed, empty channel do?

  • Blocks forever
  • Returns immediately with the zero value and ok == false
  • Panics
  • Returns the last value that was sent
Answer

Returns immediately with the zero value and ok == false — Only sending on or closing a closed channel panics; receiving is always safe.