заменить канал во время итерации - PullRequest
1 голос
/ 10 января 2020

Я хочу заменить канал на новый при некоторых условиях, например:

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 "привет", затем "мир", но это не так работать таким образом. Мне не очень понятно, что произошло, когда я переназначил канал. Есть предложения?

1 Ответ

3 голосов
/ 10 января 2020

Вы используете for range, а для Spe c: Для операторов выражение диапазона вычисляется только один раз.

Оценивается выражение диапазона x один раз перед началом l oop, с одним исключением: если присутствует не более одной итерационной переменной и len(x) равно константе , выражение диапазона не оценивается.

Переменная chStr не проверяется for l oop позже, поэтому изменение ее значения не имеет никакого эффекта.

Вы не можете использовать for range, если хотите переключиться на другое channel.

Просто используйте "нормальный" l oop и получите от канала внутри него. Используйте специальную форму x, ok := <-ch, чтобы вы знали, когда канал закрыт, и чтобы вы могли оторваться от l oop (mimi c 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 Детская площадка .

...