Learn Go← Dashboard

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

go playground
Loading...

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.

go playground
Loading...
A goroutine sends to an unbuffered `chan int`. Main never receives. What happens?