Can you compare channels with ==, use them as map keys, and send channels over channels?
Yes to all three. Channel types are comparable: two channel values are equal if they came from the same make call (the same hchan pointer) or are both nil. So channels can be map keys and comparable type arguments, and you can use them in switch.
subs := map[chan Event]struct{}{} // pub/sub subscriber set
func (b *Bus) Unsubscribe(ch chan Event) {
b.mu.Lock()
defer b.mu.Unlock()
if _, ok := b.subs[ch]; ok {
delete(b.subs, ch)
close(ch) // bus owns the subscriber channels it created
}
}
Channels are first-class values, so chan chan T works too (the reply-channel pattern). Conversions between directions work only one way: a chan T is assignable to <-chan T, not the reverse. Because of that assignability, c == r compiles for c chan T and r <-chan T, and you can look up a map[<-chan T]V using a chan T. The trap is interfaces: any(c) == any((<-chan T)(c)) is false, because the dynamic types differ even though the underlying channel is the same. Keep key types consistent when keys pass through any.
More on Channels & select
- Q213What does this print? (request/response over a channel of channels)
- Q214How would you implement rate limiting using channels?
- Q216How do you gracefully shut down a service that uses channels and goroutines?
- Q217What does this print? (
breakinsideselectinsidefor) - Q218What happens to goroutines that are already blocked on a channel when it is closed?
- Q219Go has no unbounded channels. Why not, and how would you build one?