通道的声明和初始化
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循环就会退出。