# Поведение for range с каналами в Go

В Go `for v := range ch` используется для последовательного чтения из канала `ch`. Цикл завершится **только** после того, как:

- канал будет **закрыт**, и
- все значения из него будут **прочитаны**

---

## 🔁 Сценарии поведения

### 1. Канал пуст и **не закрыт**

```go
ch := make(chan string)

for v := range ch {
    fmt.Println(v)
}
```

📌 Итог: **блокировка навсегда**, цикл ждёт значения, но никто не пишет.

---

### 2. В канале есть одно значение, канал **не закрыт**

```go
ch := make(chan string)

go func() {
    ch <- "hello"
}()

for v := range ch {
    fmt.Println(v)
}
```

📌 Итог: `hello` выведется, затем цикл **зависнет**, ожидая следующего значения.

---

### 3. В канале есть значение, потом ещё одно, затем закрытие

```go
ch := make(chan string)

go func() {
    ch <- "one"
    time.Sleep(1 * time.Second)
    ch <- "two"
    close(ch)
}()

for v := range ch {
    fmt.Println(v)
}
```

📌 Итог:

- `one` будет прочитан
- цикл подождёт
- `two` будет прочитан
- после `close(ch)` — цикл завершится

---

## ✅ Правильное завершение горутины через канал и WaitGroup

```go
import (
    "fmt"
    "sync"
)

func worker(id int, jobs <-chan int, wg *sync.WaitGroup) {
    defer wg.Done()
    for job := range jobs {
        fmt.Printf("Worker %d processing job %d\n", id, job)
    }
}

func main() {
    jobs := make(chan int)
    var wg sync.WaitGroup

    for w := 1; w <= 2; w++ {
        wg.Add(1)
        go worker(w, jobs, &wg)
    }

    for j := 1; j <= 5; j++ {
        jobs <- j
    }

    close(jobs)  // 🔑 важно закрыть канал
    wg.Wait()    // 🔒 ждём завершения всех воркеров
}
```

---

## 🧠 Общее поведение `range` по каналам

<table id="bkmrk-%D0%A1%D1%86%D0%B5%D0%BD%D0%B0%D1%80%D0%B8%D0%B9-%D0%9F%D0%BE%D0%B2%D0%B5%D0%B4%D0%B5%D0%BD%D0%B8%D0%B5-%D0%9A"><thead><tr><th id="bkmrk-%D0%A1%D1%86%D0%B5%D0%BD%D0%B0%D1%80%D0%B8%D0%B9">Сценарий</th><th id="bkmrk-%D0%9F%D0%BE%D0%B2%D0%B5%D0%B4%D0%B5%D0%BD%D0%B8%D0%B5">Поведение</th></tr></thead><tbody><tr><td>Канал пуст и не закрыт</td><td>❌ Блокировка</td></tr><tr><td>Есть 1 значение, канал не закрыт</td><td>✅ Прочтёт 1, потом зависнет</td></tr><tr><td>Есть значения, канал закрыт после них</td><td>✅ Прочтёт все, завершит цикл</td></tr><tr><td>Канал закрыт сразу</td><td>✅ Завершит цикл (если пуст)</td></tr></tbody></table>

---

## 📌 Рекомендации

- ✅ **Закрывай канал**, если больше не будет отправок
- ✅ Используй `sync.WaitGroup`, чтобы ждать завершения горутин
- ⚠️ Избегай чтения из **открытых, но не используемых** каналов