为什么通道类型中带有“ <-”?

This works.

var tick <-chan time.Time = time.Tick(1e8)

However, this does not.

var tick chan time.Time = time.Tick(1e8)

Why do I need a <- in my type declaration for a channel? I thought that <- was for writing to or reading from a channel. Why would it appear in a type?

Channels can have a type indicating whether it is readonly, writeonly or both.

Indicating a channel direction is done with <- as part of the type or omitted for a read/write channel.

So the <- in <-chan time.Time is part of the type,

chan   time.Time  //Would be a read/writable channel
chan<- time.Time  // Would be a write only channel
<-chan time.Time  // Would be a read only channel

and time.Tick(1e8) returns a read only channel.

Read more in the language spec here

A good way to think of channels is as pipes with two ends. One end is where the events flow in and the other where they flow out. So declaring a channel, e.g.

var c = make(chan int)

creates a channel as a whole - i.e. with both ends. Conversely,

func consume(c <-chan int) {
    ...
}

defines a function with a channel input parameter - i.e. the readable end of a channel, and

func generate(c chan<- int) {
    ...
}

defines a function with a channel output parameter - i.e. the writable end of a channel. Both these functions can have the whole channel passed as their actual parameter, or just the end they need.

The same general principle applies when channels are used as local variables or as fields in structs.

It's good practice to use the channel-end syntax wherever possible, because the compiler will be able to check more thoroughly that you've written what you intended.

Interestingly, the occam programming language also has equivalent syntax to mark which end of a channel is which.

While you can declare an actual "read only" or "write only" channel variable, it's useless to do so, because you can't do anything with them.

The "read only" and "write only" syntax is for function parameters. This syntax is more like "const" in C or "in" and "out" in Ada.

Nor do Go channels have two "ends". UNIX pipes have two file descriptors, one for each end. The same variable of channel type is used for both reading and writing.