Go⚡Concurrencyintermediate
Channel Direction
Go · Concurrency · Run with go run
Explanation
A channel type can be restricted to send-only (`chan<- T`) or receive-only (`<-chan T`). A bidirectional `chan T` converts implicitly to either restricted form, but not the reverse. Declaring direction in function signatures documents intent and lets the compiler catch misuse — a producer can't accidentally read, a consumer can't accidentally write.
Real-World Scenario
In a producer/consumer pipeline, the `producer` function takes a `chan<- Job` (it may only send) and the `worker` function takes a `<-chan Job` (it may only receive). The restriction is enforced at compile time, making the data-flow direction obvious and tamper-proof.
Quick Snippet
snippet.go
// Send-only parameter — function may only write
func produce(out chan<- int) {
for i := 0; i < 3; i++ {
out <- i
}
close(out)
}
// Receive-only parameter — function may only read
func consume(in <-chan int) {
for v := range in {
fmt.Println(v)
}
}
ch := make(chan int) // bidirectional
go produce(ch) // passed as chan<- int
consume(ch) // passed as <-chan intFull Example
channel_direction.go
// Compile: go run channel_direction.go
// Output:
// 0
// 1
// 2
package main
import "fmt"
// Send-only parameter — may only write to the channel
func produce(out chan<- int) {
for i := 0; i < 3; i++ {
out <- i
}
close(out)
}
// Receive-only parameter — may only read from the channel
func consume(in <-chan int, done chan<- struct{}) {
for v := range in {
fmt.Println(v)
}
done <- struct{}{}
}
func main() {
ch := make(chan int) // bidirectional
done := make(chan struct{})
go produce(ch) // passed as chan<- int
go consume(ch, done) // passed as <-chan int
<-done
}
Run command
go run channel_direction.go