https://books.studygolang.com/gopl-zh/ch8/ch8-04.html

GO Routine is golang core advantage towards other launguages, it makes async programming much easier and deliver async vars so smoothly.

Following example shows how chan and async work with its async vars:

package main

import (
	"fmt"
	"time"
)

func scheduledNotification(t time.Duration) <-chan struct{} {
	ch := make(chan struct{}, 1) //make a chan var only accept one input each time, others need to wait
	go func() {
		time.Sleep(t)
		ch <- struct{}{} //giving empty ch value, the actuall result is only to reflect time waited println.
	}()
	return ch
}

func main() {
	fmt.Println("send first")
	<-scheduledNotification(time.Second)
	fmt.Println("secondly send")
	<-scheduledNotification(time.Second)
	fmt.Println("lastly send")
}

Another way to declare return in a chan func, return <- instead of chan itself:

package main

import (
	"fmt"
	"time"
)

func scheduledNotification(t time.Duration) struct{} {
	ch := make(chan struct{}, 1) //make a chan var only accept one input each time, others need to wait
	go func() {
		time.Sleep(t)
		ch <- struct{}{} //giving empty ch value, the actuall result is only to reflect time waited println.
	}()
	return <-ch
}

func main() {
	fmt.Println("send first")
	scheduledNotification(time.Second)
	fmt.Println("secondly send")
	scheduledNotification(time.Second)
	fmt.Println("lastly send")
}

We can declare a new channel using the chan keyword, and we can close a channel using the close() function. So, if we block the code using the <- channel syntax to read from the channel, once completed, we can close it. The mark <- ch means ch is sending, while ch <- means we are passing value to ch.

func f1(c chan int, x int) {
 fmt.Println(x)
 c <- x
}

func f2(c chan<- int, x int) {
 fmt.Println(x)
 c <- x
}

Although both functions implement the same functionality, their definitions are slightly different. The difference is created by the <- symbol found on the right of the chan keyword in the definition of the f2() function.

This denotes that the c channel can only write. If the code of a Go function attempts to read from a write-only channel (also known as a send-only channel) parameter, the Go compiler generates the following error message:

# command-line-arguments
a.go:19:11: invalid operation: range in (receive from send-only type chan<-int)

Similarly, we can have the following function definitions:

func f1(out chan<- int64, in <-chan int64) {
  fmt.Println(x)
  c <- x
}

func f2(out chan int64, in chan int64) {
  fmt.Println(x)
  c <- x
}

The definition of f2() combines a read-only channel named in with a write-only channel named out. If we accidentally try to write and close a read-only channel (also known as a receive-only channel) parameter of a function, we get the following error message:

# command-line-arguments
a.go:13:7: invalid operation: out <- i (send to receive-only type <-chan int)
a.go:15:7: invalid operation: close(out) (cannot close receive-only 
channel)

为了表明这种意图并防止被滥用,Go语言的类型系统提供了单方向的channel类型,分别用于只发送或只接收的channel。类型chan<- int表示一个只发送intchannel,只能发送不能接收。相反,类型<-chan int表示一个只接收intchannel,只能接收不能发送。(箭头<-和关键字chan的相对位置表明了channel的方向。)这种限制将在编译期检测。
因为关闭操作只用于断言不再向channel发送新的数据,所以只有在发送者所在的goroutine才会调用close函数,因此对一个只接收的channel调用close将是一个编译错误。

func counter(out chan<- int) { //out is write-only chan with int type
    for x := 0; x < 100; x++ {
        out <- x
    }
    close(out)
}

func squarer(out chan<- int, in <-chan int) {	//in is read-only chan with int type
    for v := range in {	//reads in value and send to out chan
        out <- v * v
    }
    close(out)
}

func printer(in <-chan int) {
    for v := range in {
        fmt.Println(v)
    }
}

func main() {
    naturals := make(chan int)
    squares := make(chan int)
    go counter(naturals)
    go squarer(squares, naturals)
    printer(squares)
}

Following func simluate a rocket launcher countdown process, explains how select works:

package main

import (
	"fmt"
	"os"
	"time"
)

func main() {
	abort := make(chan struct{})
	go func() {
		os.Stdin.Read(make([]byte, 1)) // read a single byte
		abort <- struct{}{} // standard method to input empty chan to trigger actions in select
	}()
	fmt.Println("Commencing countdown.  Press return to abort.")
	tick := time.Tick(1 * time.Second)
	for countdown := 10; countdown > 0; countdown-- {
		select {
		case <-tick:
			fmt.Println(countdown)
		case <-abort:
			fmt.Println("Launch aborted!")
			return	//return is like break here, for loop will continue without it, as in case tick example
		}
	}
	launch()
}

func launch() {
	fmt.Println("yes")
}