Essential Go Channels and select  Edit on GitHub      File Issue

Closing channels

You can close a channel with close(chan).

Main purpose of closing a channel is to notify worker goroutines that their work is done and they can finish.

This ensures you don’t leak goroutines.

Closing a channel ends range loop over it:

ch := make(chan string)

go func() {
	for s := range ch {
		fmt.Printf("received from channel: %s\n", s)
	}
	fmt.Print("range loop finished because ch was closed\n")
}()

ch <- "foo"
close(ch)
received from channel: foo
range loop finished because ch was closed

A receive from closed channels returns zero value immediately:

ch := make(chan string)
close(ch)
v := <-ch
fmt.Printf("Receive from closed channel immediately returns zero value of the type: %#v\n", v)
Receive from closed channel immediately returns zero value of the type: ""

When receiving, you can optionally test if channel is closed:

ch := make(chan int)
go func() {
	ch <- 1
	close(ch)
}()
v, isClosed := <-ch
fmt.Printf("received %d, is channel closed: %v\n", v, isClosed)
v, isClosed = <-ch
fmt.Printf("received %d, is channel closed: %v\n", v, isClosed)
received 1, is channel closed: true
received 0, is channel closed: false

Closing channel twice panics:

ch := make(chan string)
close(ch)
close(ch)
panic: close of closed channel

goroutine 1 [running]:
main.main()
	/books/go/0220-channels-select/close4.go:7 +0x57
exit status 2

Sending to closed channel panics.

ch := make(chan int)
close(ch)
ch <- 5 // panics
panic: send on closed channel

goroutine 1 [running]:
main.main()
	/books/go/0220-channels-select/close5.go:7 +0x63
exit status 2
  ↑ ↓ to navigate     ↵ to select     Esc to close