【问题标题】:replace channel while iterating迭代时替换通道
【发布时间】:2020-01-10 17:55:25
【问题描述】:

我想在某些情况下将频道替换为新频道,例如:

package main

import (
    "log"
    "time"
)

func subMsg(s string) chan string {
    ch := make(chan string)
    go func() {
        ticker := time.NewTicker(time.Second * 2)
        for range ticker.C {
            ch <- s
        }
    }()

    return ch
}

func main() {
    chStr := subMsg("hello")

    go func() {
        i := 0
        for s := range chStr {
            log.Print(s)
            i++
            if i > 5 {
                log.Print("new topic")
                i = 0

                chStr = subMsg("world")
            }
        }
    }()

    select {}
}

我希望这段代码 sn-p 输出 5 个“hello”,然后是“world”,但它并没有这样工作。我不太清楚重新分配频道时发生了什么。有什么建议吗?

【问题讨论】:

    标签: go channel


    【解决方案1】:

    您正在使用for range,并且根据Spec: For statements,范围表达式只计算一次。

    范围表达式x在循环开始前被计算一次,有一个例外:如果最多存在一个迭代变量并且len(x)constant,则不计算范围表达式。

    chStr 变量稍后不会被 for 循环检查,因此更改其值无效。

    如果你想切换到另一个频道,你不能使用for range

    只需使用“正常”循环并从其中的通道接收。使用特殊形式x, ok := &lt;-ch,这样您就可以知道通道何时关闭,从而可以中断循环(模仿for range 的工作方式):

    for {
        s, ok := <-chStr
        if !ok {
            break
        }
        log.Print(s)
        i++
        if i > 5 {
            log.Print("new topic")
            i = 0
    
            chStr = subMsg("world")
        }
    }
    

    Go Playground 上试试。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2011-08-26
      • 1970-01-01
      • 2016-02-06
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多