Concurrency · 3 MIN READ

range over a channel ends when it closes

Drain a channel with range, and close it from the sender.

The Tour's "Range and Close" page: v, ok := <-ch sets ok to false once the channel is closed and empty. for v := range ch is that loop written once. Only the sender closes. Sending after a close panics. Closing is not required for the garbage collector — only for telling a range there is nothing more.

Channels are not files. Most of them never close, because nobody is ranging. Close when a range (or an ok-receive) needs the signal.

SEE THE IDEA

The receiver drains before the loop ends

  1. 01

    Queue

    go
    ch <- value

    Values may already be buffered

  2. 02

    End production

    go
    close(ch)

    No new sends are allowed

  3. 03

    Drain and stop

    go
    for v := range ch

    Ends after the buffer is empty

A closed channel may still contain unread values.

In practice

Use range when the entire stream should be consumed until its producer finishes. If cancellation is also required, use a select loop and inspect the two-result receive. Assign close ownership to the producer or the coordinator that knows all producers are done.

Watch out

Ranging over a nil channel blocks forever. A never-closed stream also never ends by itself.

Official reference ↗

Work through the exercise

go
package main

// Drain reads every value until ch closes and returns them in
// the order they arrived.
func Drain(ch <-chan int) []int {
	return nil
}

func main() {}
Try it yourself

Trace each value and write down your reasoning. Copy the source into GopherForge or your local Go environment to compile and check it. This web page does not execute your code or send it to a compiler service.

Progress stays in this browser. No account needed.