未初始化的通道表现如何?

I have a struct that holds a channel that is not initialized.

When I write into it, the routine is blocking as expected but the reader is never notified that something is in the pipe.

I am surprised that there is no error and I am wondering what is doing Go.

In the example bellow, neither the message pushed nor got it are printed. (Uncomment the intialization and it will work like a charm)

type MyStruct struct {
    over chan bool
}

func main() {
    nonInitialized := &MyStruct{}
    // nonInitialized.over = make(chan bool)
    go func() {
        for i := 0; i < 10; i++ {
            select {
            case <-nonInitialized.over:
                fmt.Println("got it")
            default:
                // proceed
            }
            fmt.Println("do some stuff")
            time.Sleep(10 * time.Millisecond)
        }
        panic("took too long")
    }()
    // push on the non initialized channel
    fmt.Println("pushing")
    nonInitialized.over <- true
    fmt.Println("pushed")
}

Here is the playground https://play.golang.org/p/76zrCuoeoh

(I know I should initialize the channel, this is not the purpose of the question, I want to know what is happening in Go with non initialized channels.)

An "uninitialized" field or variable of channel type will have the zero value of all channel types which is nil. So let's examine how a nil channel or operations on it behave.

It is worth collecting the channel axioms in one post:

Reasoning for blocking in case of nil channels: if a channel value is nil, no one has a reference to it, so no one will ever be ready to receive from it (what we want to send); or send anything on it (what we would receive from it).

You can read further reasoning and more details about this in Dave Cheney: Channel Axioms.

For completeness:

  • Closing a nil channel causes a run-time panic (just like closing an already closed channel).
  • Length and capacity of a nil channel is 0; in accordance with nil slices and maps having 0 length and capacity.

Reasoning: "closed" is a state, but a nil channel cannot have a state (there is only one nil channel, and not one for "closed" and one for "not closed" channel). And there are no elements queued in a nil channel (so len = 0), and it does not have a buffer capacity (so cap = 0).

This is expected behavior. A send to a nil channel blocks forever. You can read about it in the specs here: https://golang.org/ref/spec#Send_statements

The same is also applicable for a recieve on a nil channel. (https://golang.org/ref/spec#Receive_operator)

You can also keep this link handy for reference: http://dave.cheney.net/2014/03/19/channel-axioms