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.

results matching ""

    No results matching ""