Concurrency · 3 MIN READ

The arrow in the type is who may send

Write a producer that takes chan<- int and closes it.

The Tour writes ch <- v and v := <-ch and then, in Effective Go, the type itself carries the arrow: chan<- int is send-only, <-chan int is receive-only. A function that only produces values should take chan<- T. The compiler then refuses a receive in that body, which is the whole point — the restriction is the API.

Conversion is one way: a bidirectional channel may be passed where a directional one is wanted. The other direction does not compile. Close is a send-side operation, so it belongs on chan<- T.

SEE THE IDEA

The type limits who may send or receive

  1. 01

    Owner

    go
    chan int

    Can send, receive and close

  2. 02

    Producer parameter

    go
    chan<- int

    May send and close

  3. 03

    Consumer parameter

    go
    <-chan int

    May receive only

A bidirectional channel can be passed to a directional parameter.

In practice

Use direction in function signatures to communicate roles and let the compiler reject accidental reverse operations. The owner still needs a runtime lifecycle rule: a send-only parameter can close a channel, but that ability does not establish that it is the correct owner to do so.

Watch out

Direction is a permission, not an ownership guarantee. Two senders can still race to close unless the design assigns one closer.

Official reference ↗

Work through the exercise

go
package main

// Produce sends every value and then closes out. The parameter
// is send-only: a receive in this function should not compile.
func Produce(out chan<- int, values []int) {}

func main() {}
Try it yourself

Trace each value and write down your reasoning. Copy the source into GopherForge or your local Go environment to compile and check it. This web page does not execute your code or send it to a compiler service.

Progress stays in this browser. No account needed.