管道(channel)的使用

package main

import "fmt"

func main() {
   // 定义一个名为intChan的管道,该管道只能接收int64类型数据,且容量为4(即最多接收4个int64类型数据)
   intChan := make(chan int64, 4) // 等价于:var intChan chan int64 = make(chan int64, 4)

   fmt.Printf("intChan = %+v \n", intChan) // intChan = 0xc0000a4000 重要说明:管道是引用(指针)类型

   // 查询管道的长度和容量(由于还没向管道发送任何数据,此时长度为0)
   fmt.Printf("intChan的长度为:%+v,容量为:%+v \n", len(intChan), cap(intChan)) // intChan的长度为:0,容量为:4

   // 向管道发送数据
   intChan <- 1 // 发送第1个数据
   intChan <- 0 // 发送第2个数据
   intChan <- 2 // 发送第3个数据
   intChan <- 4 // 发送第4个数据(此时长度已达到容量值,再向管道发送数据就会报panic)

   // 查询管道的长度和容量(由于上面向管道发送了4个数据,故长度为4)
   fmt.Printf("intChan的长度为:%+v,容量为:%+v \n", len(intChan), cap(intChan)) // intChan的长度为:4,容量为:4

   // 从管道取出数据(重要提醒:按照先进先出的规则)
   int1 := <-intChan // 注:也可以用『int1, success := <-intChan』的方式取数据
   int2 := <-intChan
   int3 := <-intChan
   fmt.Printf("int1、int2、int3 分别为 %+v%+v%+v \n", int1, int2, int3)
   // int1、int2、int3 分别为 1、0、2
   // 重要提醒:用『int1, success := <-intChan』的方式取数据,第二个返回值表示取得的值是否为管道里的正常数据,这和管道是否已关闭没
   //           有必然联系,就算管道已关闭,但管道里仍有数据未被取出,此时取值取出的就是管道里的正常数据,success就为true。与之相
   //           反,假设已关闭的管道里已经没有数据了,此时取值取出的就不是管道里的正常数据,而是零值,则success为false。

   // 查询管道的长度和容量(由于上面向管道发送了4个数据,又从管道取出了3个数据,还剩1个数据,故长度为1)
   fmt.Printf("intChan的长度为:%+v,容量为:%+v \n", len(intChan), cap(intChan)) // intChan的长度为:1,容量为:4

   // 关闭管道(重要提醒:管道关闭后不能再向其发送数据,但仍然可以从中取出数据)
   close(intChan)

   // 遍历管道(重要提醒:遍历管道是遍历其现有的数据,跟管道容量无关,且必须关闭管道后才能遍历管道,否则会报panic)
   for value := range intChan {
      fmt.Printf("value = %+v \n", value)
   }
   // value = 4
}

//========== 总结 ==========//
// 1、管道的本质就是一个队列,既然是队列那就有先进先出(FIFO,First In First Out)的特点,即先发送给管道的数据会被先取出。
// 2、管道在定义时需要指定数据类型(可以为int、string、map等各种数据类型)和容量,并且后续无法再修改数据类型和容量。
// 3、管道和切片一样,有长度(len)和容量(cap)两个属性,当长度已经达到容量了还向管道发送数据就会报panic,从一个未关闭且长度为0的管道
//    执行取数据操作也会报panic。
// 4、管道的发送数据和取出数据都是通过“<-”符号来操作,根据箭头指向可以很直观地看到是向管道发数据还是从管道取数据。
// 5、管道关闭后不能再向其发送数据,但仍然可以从中取出数据,且无论管道里是否有数据都能取到值,当最后一个数据被取出后,再从管道里取值就
//    只能取得零值(注:零值指的是数字0、空字符串、false等值)。
// 6、遍历管道是遍历其现有的数据,跟管道容量无关,且必须关闭管道后才能遍历管道,否则会报panic。
// 7、管道是线程安全的,多个协程操作同一个管道不会发生资源竞争的问题,这也是管道的主要价值。
// 8、Go提供了函数关闭管道,但是没有提供函数检查管道是否关闭,这不是Go官方的疏忽,而是希望开发者遵循管道只能由数据发送方来关闭的原则。

Copyright © 2024 码农人生. All Rights Reserved