首页 > 解决方案 > 迭代时替换通道

问题描述

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

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 {}
}

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

标签: gochannel

解决方案


您正在使用for range, 并且每个规范:对于语句,范围表达式仅评估一次。

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

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

for range如果要切换到另一个频道,则无法使用。

只需使用“正常”循环并从其中的通道接收。使用特殊形式x, ok := <-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上尝试一下。


推荐阅读