nil channel VS closed channel
The zero value of channel type is nil
, and the send and receive operations on a nil
channel will always block. Check the following example:
package main
import "fmt"
func main() {
var ch chan int
go func(c chan int) {
for v := range c {
fmt.Println(v)
}
}(ch)
ch <- 1
}
The running result is like this:
fatal error: all goroutines are asleep - deadlock!
goroutine 1 [chan send (nil chan)]:
main.main()
/root/nil_channel.go:14 +0x64
goroutine 5 [chan receive (nil chan)]:
main.main.func1(0x0)
/root/nil_channel.go:9 +0x53
created by main.main
/root/nil_channel.go:12 +0x37
We can see the main
and func
goroutines are both blocked.
The Go
's built-in close
function can be used to close the channel which must not be receive-only, and it should always be executed by sender, not receiver. Closing a nil
channel will cause panic. See the following example:
package main
func main() {
var ch chan int
close(ch)
}
The running result is like this:
panic: close of nil channel
goroutine 1 [running]:
panic(0x456500, 0xc82000a170)
/usr/local/go/src/runtime/panic.go:481 +0x3e6
main.main()
/root/nil_channel.go:5 +0x1e
Furthermore, there are also some subtleties of operating an already-closed channel:
(1) Close an already channel also cause panic:
package main
func main() {
ch := make(chan int)
close(ch)
close(ch)
}
The running result is like this:
panic: close of closed channel
goroutine 1 [running]:
panic(0x456500, 0xc82000a170)
/usr/local/go/src/runtime/panic.go:481 +0x3e6
main.main()
/root/nil_channel.go:6 +0x4d
(2) Send on a closed channel will also introduce panic:
package main
func main() {
ch := make(chan int)
close(ch)
ch <- 1
}
The running result is like this:
panic: send on closed channel
goroutine 1 [running]:
panic(0x456500, 0xc82000a170)
/usr/local/go/src/runtime/panic.go:481 +0x3e6
main.main()
/root/nil_channel.go:6 +0x6c
(3) Receive on a closed channel will return the zero value for the channel's type without blocking:
package main
import "fmt"
func main() {
ch := make(chan int)
close(ch)
fmt.Println(<-ch)
}
The executing result is like this:
0
The following is a summary of "nil
channel VS closed channel":
Operation type | Nil channel | Closed channel |
---|---|---|
Send | Block | Panic |
Receive | Block | Not block, return zero value of channel's type |
Close | Panic | Panic |
References:
Package builtin;
Is it OK to leave a channel open?;
The Go Programming Language Specification.