Как работает оператор `range` с каналами в Go?

Ответ

Да, оператор range можно использовать для итерации по значениям, поступающим из канала. Цикл for ... range автоматически считывает данные из канала до тех пор, пока он не будет закрыт.

Принцип работы:

  1. Цикл блокируется, ожидая поступления нового значения в канал.
  2. Когда значение приходит, оно присваивается переменной итерации, и тело цикла выполняется.
  3. Это повторяется для каждого значения.
  4. Когда канал закрывается (close(channel)) и все значения из его буфера прочитаны, цикл range завершается.

Пример:

package main

import "fmt"

func main() {
    ch := make(chan int, 3) // Буферизованный канал

    go func() {
        defer close(ch) // Важно закрыть канал, чтобы range завершился
        for i := 1; i <= 5; i++ {
            ch <- i
        }
    }()

    // Цикл будет читать из канала, пока он не будет закрыт и пуст
    for value := range ch {
        fmt.Println("Получено:", value) // Выведет от 1 до 5
    }

    fmt.Println("Канал закрыт, цикл завершен.")
}

Ключевые моменты:

  • Deadlock: Если вы используете range на канале, который никогда не закроется, а все отправляющие горутины завершились, программа впадет в deadlock, так как цикл будет вечно ждать новых данных.
  • Nil-канал: Использование range на nil-канале приведет к вечной блокировке, даже если канал никто не собирается закрывать (так как nil-канал всегда блокирует операции чтения и записи).