Another possibility when handling channel variables is specifying whether they are only for sending or only for receiving data. This is indicated by the <- arrow, which will precede chan if it's just for receiving, or follow it if it's just for sending:
func main() {
var a = make(chan int)
s, r := (chan<- int)(a), (<-chan int)(a)
fmt.Printf("%T - %T", s, r)
}
The full example is available at https://play.golang.org/p/ZgEPZ99PLJv.
Channels are already pointers, so casting one of them to its send-only or receive-only version will return the same channel, but will reduce the number of operations that can be performed on it. The types of channels are as follows:
- Send only channels, chan<-, which will allow you to send items, close the channel, and prevent you from sending data with a compile error.
- Receive only channel, <-chan, that will allow you to receive data, and any send or close operations will be compiling errors.
When a function argument is a send/receive channel, the conversion is implicit and it is a good practice to adopt because it prevents mistakes such as closing the channel from the receiver. We can take the other example and make use of the one-way channels with some refactoring.
We can also create a function for sending values that uses a send-only channel:
func send(ch chan<- int, max int) {
for i := 0; i < max; i++ {
ch <- i
}
close(ch)
}
Do the same thing for receiving using a receive-only channel:
func receive(ch <-chan int) {
for v := range ch{
fmt.Println(v)
}
}
And then, use them with the same channel that will be automatically converted in the one-way version:
func main() {
var a = make(chan int)
go send(a, 10)
receive(a)
}
The full example is available at https://play.golang.org/p/pPuqpfnq8jJ.