var ch chan int //声明
ch = make(chan int) //初始化
ch1 := make(chan int)//也可使用一句话初始化
ch2 := make(chan int,10) //初始化一个缓冲为10的通道
ch <- 10//把10发入通道里面
无缓冲通道的接收发送
我们先看下面的代码
var ch chan int
ch = make(chan int)
//通道有send,receive,close三种操作
ch <- 10//把10发入通道里面
x := <- ch //从通道中接收并赋值给变量x
fmt.Println(x)
上面的代码是会报错的,我们在给无缓冲通道发送值的时候,必须要启动一个goroutine去取值
package main
import (
"fmt"
"time"
)
//通道的声明格式如下
func main() {
var ch chan int
ch = make(chan int)
go recv(ch)//开启一个协程来接收通道的值,并且接收需要放在发送的前方
ch <- 10//把10发入通道里面
time.Sleep(time.Second)//防止主线程结束后,程序直接退出
}
func recv( c chan int) {
ret := <-c
fmt.Println("接收成功",ret)
}
有缓冲通道的接收和发送
import "fmt"
//通道的声明格式如下
func main() {
ch := make(chan int,1)//声明一个缓冲是1的通道
ch <- 10
fmt.Println("发送成功")
ch <- 11 //通道的缓冲是1,只能存放一个元素,此时将报错
}
解决办法是我们可以把之前的元素发送出去
package main
import "fmt"
//通道的声明格式如下
func main() {
ch := make(chan int,1)
ch <- 10
fmt.Println("发送成功")
<- ch //把通道中的值发送出去,并忽略结果
ch <- 11
}
无缓冲通道顺序取值
package main
import (
"fmt"
"time"
)
func main() {
c := make(chan int)//无缓冲的通道
go func() {
for i := 0; i < 3; i++ {
time.Sleep(time.Second)
c <- i//如果下方的for循环还没有取值的话,此处会堵塞等待for取值,所以可以达到顺序输出的结果
}
close(c)//通道不再接收值了,我们可以关闭通道了,当通道关闭的时候,我们再从通道里面取值的话,就会返回零值
//如果我们不关闭通道的话,我们还从通道中取值,那此时就会报死锁错误
}()
for {
if data, ok := <-c; ok {
fmt.Println(data)
} else {
fmt.Println(data)//此时我们取去的应该是一个对应通道类型的零值
break
}
}
fmt.Println("main结束")
}
注意:关闭的通道是可以取值的,取出的值都是通道对应类型的零值;关闭通道是不可以发送值的,如果发送,将会报panic。
优雅的从通道循环取值func main() {
ch1 := make(chan int)
ch2 := make(chan int)
// 开启goroutine将0~100的数发送到ch1中
go func() {
for i := 0; i < 100; i++ {
ch1 <- i //如果下方的go程没有取值,此处堵塞等待
}
close(ch1)
}()
// 开启goroutine从ch1中接收值,并将该值的平方发送到ch2中
go func() {
for {
i, ok := <-ch1 // 通道关闭后再取值ok=false
if !ok {
break
}
ch2 <- i * i
}
close(ch2)
}()
// 在主goroutine中从ch2中接收值打印
for i := range ch2 { // 通道关闭后会退出for range循环
fmt.Println(i)
}
}
通过上述代码,可以看到,判断通道是否关闭有两种方式,一种方式是对通道取值的返回值判断,一种是通过for range遍历通道,如果通道关闭,for range循环就会退出。