go - 封闭 channel 发送值为零吗?

标签 go

在下面的代码中:

package main

import (
    "fmt"
    "time"
)

func asChan(vs ...int) <-chan int {
    c := make(chan int)
    go func() {
        for _, v := range vs {
            c <- v
            time.Sleep(2 * time.Second)
        }
        close(c)
    }()
    return c
}

func merge(a, b <-chan int) <-chan int {
    c := make(chan int)

    go func() {
        for {
            select {
            case v := <-a:
                c <- v
            case v := <-b:
                c <- v
            }
        }
    }()

    return c
}

func main() {
    a := asChan(1, 3, 5, 7)
    b := asChan(2, 4, 6, 8)

    c := merge(a, b)

    for value := range c {
        fmt.Println(value)
    }
}

下面是 v 的零值关闭 channel 后收到a .

enter image description here

但我的理解是,case v := <-a: 中的这行代码(merge())函数应该阻塞输入,因为 channel ( a )已关闭

编辑:

代码更改后,main()不退出:
func merge(a, b <-chan int) chan int {
    c := make(chan int)

    go func() {
        defer close(c)

        for a != nil || b != nil { // while atleast one channel is open
            select {
            case v, ok := <-a:
                sendOnChannel(a, c, v, ok)
            case v, ok := <-b:
                sendOnChannel(b, c, v, ok)
            }
        }
    }()

    return c
}

func sendOnChannel(sourceChan <-chan int, targetChan chan int, v int, channelOpen bool) {
    if !channelOpen {
        // The channel is closed. Set channel variable
        // to nil to disable this select / case.
        sourceChan = nil
    } else {
        targetChan <- v
    }
}

输出:
$ bin/cs61a 
1
2
3
4
5
6
7
8

如何a在这行代码中生成零(case v := <-a)?

最佳答案

specification says :

A receive operation on a closed channel can always proceed immediately, yielding the element type's zero value after any previously sent values have been received.



我不知道语言设计者为什么选择这种设计,但它在实践中很有用。

使用二值接收语句来检测 channel 何时因为 channel 关闭而产生零值。
v, ok := <-a
if !ok {
   // channel closed
}

使用以下代码实现合并:
func merge(a, b <-chan int) <-chan int {
    c := make(chan int)
    go func() {
        defer close(c)

        // While we have at least one channel ...

        for a != nil || b != nil {
            select {
            case v, ok := <-a:
                if ok {
                    c <- v
                } else {
                    // The channel is closed. Set channel variable
                    // to nil to disable this select / case.
                    a = nil 
                }
            case v, ok := <-b:
                if ok {
                    c <- v
                } else {
                    b = nil
                }
            }
        }
    }()
    return c
}

Run it on the playground .

关于go - 封闭 channel 发送值为零吗?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/61706675/

相关文章:

Golang自定义超时解决方案

go - 模板部分呈现为纯文本

go - 在 golang 中管理错误

go - 当没有这样的文件返回 err 为 nil 时如何使用 os.Open

go - Fyne布局中的填充

linux - 顺序读取记录时大文件的内容被破坏

angular - 使用 go 提供 Angular dist 文件夹

go - 为什么访问是 RDWR 时内存映射文件需要刷新?

函数的命名约定

go - 如何解析文本并将其格式化以将其作为 json 数据发送