【问题标题】:Why never reached the return statement为什么从来没有达到return语句
【发布时间】:2015-01-16 06:59:43
【问题描述】:

看下面的代码sn-p

package main

import (
    "fmt"
    "time"
)

func sender(ch chan string) {

    ch <- "Hello"
    ch <- "Foo"
    ch <- "and"
    ch <- "Boo"
    close(ch)
}

func main() {

    ch := make(chan string)

    go sender(ch)

    for {
        select {
        case value := <-ch:
            fmt.Println(value)
        case <-time.After(time.Second * 2):
            fmt.Println("Return")
            return
        }
    }
}

结果我得到了空白输出和 time.After 将永远无法到达。为什么?

我注意到,当我尝试从关闭的通道接收值时,它将从类型接收零值。为什么我仍然可以从封闭的渠道获得价值?

我也可以检查,

v, ok := <-ch

如果 ok 为 false,则通道关闭。

【问题讨论】:

  • 您的程序打印在sender() 函数中发送的单词,然后继续打印空行,即string 的零值,当从关闭的通道接收时返回此零值。尝试删除 close(ch) 看看会发生什么。

标签: go


【解决方案1】:

在 for 循环的每次迭代中都会创建一个新的两秒计时器。关闭的通道随时准备接收。代码永远循环,因为在关闭的通道准备好接收之前,新计时器的通道永远不会准备好接收。

解决问题的一种方法是将通道设置为 nil:

    case value, ok := <-ch:
        if !ok {
            ch = nil
        } else {
            fmt.Println(value)
        }

在 nil 通道上接收永远不会准备好。

playground example

如果您希望循环最多运行两秒钟,那么您应该在循环之外创建计时器:

    after := time.After(time.Second * 2)

并在循环中选择这个计时器:

    case <-after:
        fmt.Println("Return")
        return

playground example(添加睡眠以使示例在操场上运行)

您可以将通道设置为 nil 并在循环之外创建计时器。

playground example

【讨论】:

  • Closed channels are always ready to receive 瘦是什么意思?我每次都可以在封闭的频道上接收?
  • @zero_coding 我更新了这句话,说关闭的频道总是准备好接收。换句话说,在封闭的通道上接收永远不会阻塞。
猜你喜欢
  • 2021-02-12
  • 2017-05-22
  • 2019-09-17
  • 2022-11-20
  • 1970-01-01
  • 1970-01-01
  • 2017-12-22
  • 2021-05-06
  • 1970-01-01
相关资源
最近更新 更多