Essential Go Channels and select  Suggest an edit

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()
	/private/var/folders/2k/p2_4052s70vd5_cfdm0k0l740000gn/T/src878350153/main.go:8 +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()
	/private/var/folders/2k/p2_4052s70vd5_cfdm0k0l740000gn/T/src078531604/main.go:8 +0x63
exit status 2
  ↑ ↓ to navigate     ↵ to select     Esc to close