Go's typed pipes — communicate, don't share memory.
Channel Basics
A channel is a typed pipe. One goroutine sends values in; another receives them. The send blocks until the receiver is ready, and vice versa — that's how goroutines coordinate without sharing memory directly.
Creating and using
ch := make(chan int) // unbuffered channel of int
ch <- 42 // send 42 (blocks until somebody receives)
v := <-ch // receive (blocks until somebody sends)
The arrow <- is the channel operator. The channel is always on the right of
a send and on the left of a receive.
A first example
The send and the receive rendezvous — they happen at the same point in time.
There's no race on msg because the goroutine had to finish writing before the
main goroutine could read.
Unbuffered channels synchronize
Unbuffered = capacity 0 = "I'll wait for the other side". This is the simplest and the most useful form. It gives you both data transfer and synchronization in one operation.
done := make(chan struct{})
go func() {
work()
done <- struct{}{} // signal completion
}()
<-done // wait for it
A chan struct{} is the idiom for "signal only, no data" — struct{} is zero
bytes.
Channels are typed
chan int // bidirectional
chan<- int // send-only — can only put values in
<-chan int // receive-only — can only pull values out
You can pass a chan int where chan<- int or <-chan int is expected. This
lets you tell callers "you can only send" or "you can only receive" through the
function signature.