CodeNebula
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 int

Full 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