Что это означает, когда один канал использует две стрелки для записи в другой канал в go - PullRequest
1 голос
/ 03 февраля 2020

Это пример кода из книги Concurrency в Go. Внутри блока выбора находится следующий оператор

case takeStream <- <- valueStream:

Я не могу понять, что делают двойные стрелки, и в тексте нет объяснения. Выходные данные меняются, когда я заменяю его на

case takeStream <- valueStream:

, так что это явно необходимо

Полная функция:

func take(done<- chan interface{}, valueStream <- chan interface{}, num int) <- chan interface{}{
    takeStream := make ( chan interface{})
    go func() {
        defer close(takeStream)
        for i := 0; i < num; i ++ {
            select {
            case <- done :
                return
            case takeStream <- <- valueStream:
            }
        }
    }()

    return takeStream
}

Отредактировано: Если я правильно понимаю, утверждение расширилось было бы

i := 5
valueStream <- i
tmp <- valueStream
takeStream <- tmp

, поэтому

takeStream <- <- valuesStream

является ярлыком

Это объясняет, почему, когда я позвонил

fmt.Println(<-takeStream)

, я получил прикольные числа - предположительно некоторые цифры c представление значения Stream

Спасибо!

1 Ответ

6 голосов
/ 03 февраля 2020

takeStream <- <- valueStream - это объединение операции получения ( оператор получения ) и оператор отправки .

Оператор получения является унарным оператором и, как таковой, , имеет наивысший приоритет ( Spe c: операторы ), а оператор send является оператором и выходит за пределы иерархии операторов. Как следствие, c1 <- <- c2 совпадает с c1 <- (<-c2).

Таким образом, ваш пример такой же, как:

takeStream <- (<-valueStream)

(Обратите внимание, что любая другая интерпретация не будет имеет смысл.)

И Spe c: Отправить операторы:

И канал, и выражение значения оцениваются до начала связи.

Передаваемое значение должно быть оценено перед отправкой. Итак, ваш пример сначала получает значение от valueStream, а затем отправляет это значение на takeStream ...

... Или так было бы, если бы этот оператор отправки (и оператор получения) стоять самостоятельно.

При использовании внутри оператора select в качестве одного из операторов связи case, происходит следующее:

Цитирование из Spe c: Выберите операторы:

Выполнение оператора "select" выполняется в несколько этапов:

  1. Для всех случаи в операторе, операнды канала операций приема и выражения канала и правой части операторов отправки оцениваются ровно один раз, в порядке исходного кода, при вводе оператора выбора. Результатом является набор каналов для приема или отправки и соответствующие значения для отправки. Любые побочные эффекты в этой оценке будут происходить независимо от того, какая (если таковая имеется) операция связи выбрана для продолжения. Выражения в левой части RecvStmt с кратким объявлением или присваиванием переменной еще не оценены.

[...]

Поэтому, когда у вас есть это :

select {
case <- done :
    return
case takeStream <- <- valueStream:
}

Затем оценивается <-valueStream (значение получено из valueStream). Если операция блокируется, то весь select будет блокироваться (даже если done закрыт и, таким образом, готов к приему от).

Как только значение получено из valueStream, только тогда оно будет будет решено, может ли это значение быть отправлено на takeStream, и будет ли выбрано это case, если другие случаи также могут продолжаться.

Если одно или несколько сообщений может продолжаться, то одно, которое может продолжаться, выбирается с помощью равномерного псевдослучайного выбора. В противном случае, если есть случай по умолчанию, этот случай выбирается. Если регистр по умолчанию отсутствует, оператор SELECT блокируется до тех пор, пока не будет продолжено хотя бы одно из сообщений.
...