Range over Channels
Iterate over channel values until the channel is closed using a for-range loop.
A for range loop over a channel receives values until the channel is closed. This is the idiomatic way to consume a stream of values produced by a goroutine.
Launch a producer goroutine that sends values and then closes the channel. The consumer iterates with for v := range ch - the loop exits automatically when the channel closes.
package main
import "fmt"
func produce(ch chan<- int) {
for i := 1; i <= 5; i++ {
ch <- i
}
close(ch) // signals the range loop to stop
}
func main() {
ch := make(chan int)
go produce(ch)
for v := range ch {
fmt.Println(v)
}
fmt.Println("done")
}Range over channels composes naturally into pipeline patterns, where one goroutine's output channel feeds the next stage's input:
func square(in <-chan int) <-chan int {
out := make(chan int)
go func() {
for v := range in {
out <- v * v
}
close(out) // propagate the close downstream
}()
return out
}
nums := make(chan int)
go func() {
for _, n := range []int{2, 3, 4} {
nums <- n
}
close(nums)
}()
for sq := range square(nums) {
fmt.Println(sq) // 4, 9, 16
}In production
Range over a channel blocks until the channel is closed. If the sender never closes, the loop runs forever - a common goroutine leak. Always ensure the sending goroutine closes the channel, or give the loop an exit condition via a done channel or context.Context cancellation.
Enjoyed this? Get more essays on software craft delivered to your inbox.
Subscribe free