chan T 表示 T 类型的信道。
信道的零值为 nil。信道的零值没有什么用,应该像对 map 和切片所做的那样,用 make 来定义信道。
a <- 1 //表示在a里面放入1
b := <-a //将a值取出来,赋值给b
package main import ( "fmt" "time" ) func test(a chan int){ fmt.Println("你好啊!") //放值 time.Sleep(time.Second*3) //睡三秒后再打印b值 a <- 1 //表示在a里面放入1 } func main(){ var a chan int = make(chan int) //注意:一定要初始化 go test(a) b := <-a //将a值取出来,赋值给b fmt.Println(b) }
默认取值和赋值都是阻塞的。当 Go 协程给一个信道发送数据时,照理说会有其他 Go 协程来接收数据。如果没有的话,程序就会在运行时触发 panic,形成死锁。
同理,当有 Go 协程等着从一个信道接收数据时,我们期望其他的 Go 协程会向该信道写入数据,要不然程序就会触发 panic。
package main func main() { a := make(chan int) a <- 5 }
func sendData(sendch chan<- int) { // chan<- int 是只写的,如果读取信道就会报错 sendch <- 10 } func main() { // 只写信道 sendch := make(chan int) go sendData(sendch) fmt.Println(<-sendch) }
数据发送方可以关闭信道,通知接收方这个信道不再有数据发送过来。
当从信道接收数据时,接收方可以多用一个变量来检查信道是否已经关闭。
package main import ( "fmt" ) func producer(chnl chan int) { for i := 0; i < 10; i++ { chnl <- i } close(chnl) } func main() { ch := make(chan int) go producer(ch) for { v, ok := <-ch // 如果信道关闭,ok就是false // 如果没关闭,就是true if ok == false { break } fmt.Println("Received ", v, ok) } }
func producer(chnl chan int) { for i := 0; i < 10; i++ { chnl <- i } close(chnl) } func main() { ch := make(chan int) go producer(ch) for v := range ch { fmt.Println("Received ",v) } }