A channel is a typed pipe for sending values between goroutines. make(chan T) creates one; the send and receive on either end are how goroutines synchronize.
make(chan string) creates an unbuffered channel. A send blocks until another goroutine receives, and a receive blocks until another goroutine sends — the exchange itself is the synchronization.
ch := make(chan string)
go func() {
ch <- "done"
}()
msg := <-ch
fmt.Println(msg) // doneA buffered channel holds a fixed number of values with no receiver waiting. make(chan int, 2) holds two; a send only blocks once the buffer is full.
ch := make(chan int, 2)
ch <- 1
ch <- 2
fmt.Println(<-ch, <-ch) // 1 2Channel operations
| Operation | Behavior |
|---|---|
make(chan T) | Unbuffered channel of type T. |
make(chan T, n) | Buffered channel with capacity n. |
ch <- v | Sends v. Blocks if the buffer is full (or always, if unbuffered). |
v := <-ch | Receives a value. Blocks until one is available. |
v, ok := <-ch | ok is false once ch is closed and drained. |
close(ch) | Marks ch closed. Sending on it afterward panics. |
len(ch) / cap(ch) | Values currently buffered, and the buffer's total capacity. |
for v := range ch | Receives repeatedly until ch is closed. |
Closing and direction
close(ch) marks a channel as done. range over a channel receives values until it's closed, then exits the loop on its own. Close after the last send, never before, or buffered values are lost.
ch := make(chan int, 3)
ch <- 1
ch <- 2
close(ch)
for v := range ch {
fmt.Println(v)
}
// 1
// 2chan<- int accepts sends only, <-chan int accepts receives only. A bidirectional channel converts automatically when passed into either parameter, and the compiler then blocks the wrong direction inside that function.
func producer(out chan<- int) {
out <- 42
}
func consumer(in <-chan int) {
fmt.Println(<-in)
}
ch := make(chan int)
go producer(ch)
consumer(ch) // 42The buffered example, the closed-channel range, and the directional producer all run as one program: two buffered values print first, then the producer's value.
$ go run channels.go
1
2
42