从封闭通道读取for循环中的Select语句永远为零值

时间:2017-12-06 12:18:13

标签: for-loop go

鉴于此代码模拟了使用扇入模式获取3个网址的某些网站内容以及缩小频道上的范围:https://play.golang.org/p/MSkRI7x4vz

for s := range r {
    println(s)
}

这很好用,但我想使用整体超时信号通道,所以我尝试在for循环中使用select,如下所示: https://play.golang.org/p/LjDoIc0j-z

totalTimeout := time.After(300 * time.Millisecond)
loop:
    for {
        select {
        case s := <-r:
            fmt.Println(s)
        case <-totalTimeout: // signaling usage of a channel
            fmt.Println("Timed out")
            break loop
        }
    }
}

表现不佳:输入通道关闭后,扇入的压缩通道关闭。但是现在读取零值直到超时有效发生。当我阅读http://www.tapirgames.com/blog/golang-channel或规范https://golang.org/ref/spec#Close时,似乎从封闭频道接收&#34;永远不会阻止&#34;从而返回零值。我只能猜测,一个范围检测到关闭,而选择不能,因为它的条件是从一个通道本身读取。

我可以像这样突破

case s := <-r:
    if s == "" {
        break loop
    }
    fmt.Println(s)

是否有另一种方法可以停止获取空值,或者这是在for循环中使用select的正确惯用方法吗?

1 个答案:

答案 0 :(得分:4)

在收到通道中的所有元素后,在关闭的通道上接收会产生零值。

使用两个值接收来检测通道何时关闭并从循环中断开。当通道产生零值时,第二个值为false,因为通道已关闭。

for {
    select {
    case s, ok := <-r:
        if !ok {
            break loop
        }
        fmt.Println(s)
    case <-totalTimeout: // signaling usage of a channel
        fmt.Println("Timed out")
        break loop
    }
}