Go 语言基础 - channels ( 通道 ) ( 一 )

yufei       6 年, 3 月 前       845

看了这几天的文章,感觉要每天一个大类了...这也是醉了,今天我们就来看看 Go 语言中的 channel

对了,百度了一下,发现 channel 没有一个很好的中文名字,虽然我也在 「 管道 」 和 「 通道 」 两个间徘徊,但这里,我还是翻译成 「 通道 」 吧

channel 是一个循环队列,可以同步或异步地传送某种类型的值,一个 channel 可以接收来自多个发送器的值,也可以将值发送给多个接收器

术语

channel 用到了许多有趣的概念,我们将这些概念罗列在此

  • 「 Buffered 」( 可缓冲 ) - 内部缓冲区大小大于 1channel
  • 「 Empty-buffered 」( 零缓冲 ) - 内部缓冲区大小为 0channel
  • 「 Nil 」( 空值 ) - channel 显式 ( 赋值 ) 或隐式 ( 未初始化的变量 ) 设置为 nil
  • 「 Unbuffered 」( 不缓冲 ) - 不含内部缓冲区的 channel

生命周期

一个 channel 是通过调用内建函数 make() 来初始化的。此调用会根据正在创建的通道类型接收一个或两个参数。第一个参数是必须的,它表示要创建的 channel 类型,第二个参数是可选的,表示要创建的 channel 缓冲区的大小。第二个通道仅在你需要创建 「 可缓冲 」 的 channel 时才需要

一个 channel 是通过调用内建函数 close() 来关闭的。关闭 channel 的动作是可选的。但它却是发送者告诉接收者该 channel 不再接收任何值了而已 ( 不再接收任何值,也就是不再会发送任何值了 )

声明

声明一个 「 空值 」 的 int 类型的 channel

var c chan int

初始化

初始化一个 「 不缓冲 」 的 channel

c = make( chan int )

初始化一个 「 可缓冲 」的 channel,缓冲区大小为 2

c = make( chan int, 2 )

初始化一个 「 零缓冲 」 的 channel ,缓冲区大小为 0

c = make( chan int, 0 )

关闭或终止 channel

close(c)

陷阱

close(c) 这个动作,并非完美的

  1. 尝试关闭一个 nilchannel 会引发一个异常 ( panic )

    package main
    
    func main() {
        var c chan int
        close(c)
    }
    

    运行结果如下

    $ go run demo.go
    panic: close of nil channel
    
    goroutine 1 [running]:
    main.main()
        /Users/yufei/go/demo.go:5 +0x2a
    exit status 2
    
  2. 尝试关闭一个已经关闭的 channel 也会引发一个异常 ( painic )

    package main
    
    func main() {
        var c chan int
        c = make( chan int , 0 )
        close(c)
        close(c)
    }
    

    运行结果如下

    $ go run demo.go
    panic: close of closed channel
    
    goroutine 1 [running]:
    main.main()
        /Users/yufei/go/demo.go:7 +0x57
    exit status 2
    

究其原因,它仅仅是一个通知作用而已,既然缺失了通知的对象,那自然就会报错了

channel 操作

用于与 channel 交互的操作符是 <- 。它用于向 channel 发送值或从中接收值,操作类型取决于 channel 变量的位置

接收操作

从一个 channel 中接收一个值时,变量在操作符的 右边

下面的代码尝试从 channel 变量 c 中接收一个值,并保存在 value

value := <- c

下面的代码尝试从 channel 变量 c 中接收一个值,并获取该 channel 是否关闭

value, ok := <- c

当变量 ok 的值为 true 时则表示已关闭,如果为 false 则表示未关闭

下面的代码尝试从 channel 变量 c 中循环的接收值,直到 c 被关闭

for value := range c {
    // 一些其它逻辑
}

发送操作

当要往一个 channel 中发送值时,变量在操作符的左边,要发送的值在操作符的右边

c <- value

陷阱

  1. 从一个已经关闭的通道里获取值,永远不会发生阻塞
  2. 从一个已经关闭的通道获取的值,该值永远是通道类型的空值,比如,如果是 chan int ,则值为 0 ,如果是 chan string ,则值为 ""

最佳实战

如果你无法理解 <- 到底是用来接收还是用来发送,那么只要把它当作一个箭头就好了,这样就容易理解了

例如

  • <- c 是用于发送的,看这个操作,是不是很像让 c 往箭头方向看
  • c <- 是用于接收的,看这个操作,是不是很像箭头指向 c
目前尚无回复
简单教程 = 简单教程,简单编程
简单教程 是一个关于技术和学习的地方
现在注册
已注册用户请 登入
关于   |   FAQ   |   我们的愿景   |   广告投放   |  博客

  简单教程,简单编程 - IT 入门首选站

Copyright © 2013-2022 简单教程 twle.cn All Rights Reserved.