= Channels = '''Channels''' are a duck typing feature. <> ---- == Description == Channels are a pipeline. Their primary use case is passing values between two [[Go/Goroutines|goroutines]]. Channels must be initialized like: {{{ ch := make(chan string) }}} By default a channel is unbuffered, meaning that it halts on 'sends' until a value can be 'received'. To instead initialize a channel with a buffer that can queue up to N values before halting, try: {{{ ch := make(chan string, 2) }}} Values are sent and received like: {{{ func main() { ch := make(chan string) ch <- "foo" fmt.Println(<-ch) } }}} === Function Signatures === Function signatures ''can'' distinguish between a channel that can be sent on and a channel that can be received on. {{{ func i_only_send(ch chan<- string) { ch <- "foo" } func i_only_receive(ch <-chan string) { fmt.Println(<-ch) } func i_can_do_anything(ch chan string) { ch <- "foo" fmt.Println(<-ch) } }}} === Synchronization === A channel can be used in a purposefully blocking manner to force synchronization across goroutines. {{{ func worker(done chan struct{}) { time.Sleep(3 * time.Second) done <- struct{}{} } func main() { done := make(chan struct{}, 1) go worker(done) <-done //`main` waits until `worker` sends a value through `done` } }}} === Closing === Aside from sending a value, a close event can also be sent. {{{ func sending_something(ch chan<- string) { ch <- "foo" time.Sleep(3 * time.Second) close(ch) } }}} There are two ways to read the close event on the receiving side. First, by receiving the optional second value, as in: {{{ _, more := <-ch if !more { fmt.Println("no more!") } }}} This can be used like: {{{ func doing_something(ch <-chan string) { s, ok := <-ch if ok { fmt.Println(s) s, ok = <-ch } } }}} Second, when iterating over the channel, a close event ends the loop. {{{ func doing_something(ch <-chan string) { for s := range ch { fmt.Println(s) } } }}} A close event can be deferred like: {{{ defer close(ch) }}} A receiver should never close a channel. If a design like this is necessary, use two channels instead. {{{ func doing_something(rx <-chan string, tx chan<- struct{}) { for s := range rx { if s == "magic phrase" { tx <- struct{}{} return } fmt.Println(s) } } }}} === Switching === A receiver can switch between channels based on which is ready. If multiple are ready, one is picked randomly. {{{ func summation(ch chan int, quit chan struct{}) { sum := 0 for { select { case i <-ch: sum += i case <-quit: fmt.Println(sum) default: time.Sleep(3 * time.Second) } } } }}} ---- CategoryRicottone