Устранить panic при попытке записи в уже закрытый канал

Пусть горутина закроет канал после отправки, а main сразу начнёт чтение. Ожидать отправителя до начала чтения небуферизированного канала нельзя.

Короткий ответ

Что ответить на собеседовании

Пусть горутина закроет канал после отправки, а main сразу начнёт чтение. Ожидать отправителя до начала чтения небуферизированного канала нельзя.

Подробный разбор

Ответ с пояснениями

Условие

В данном примере программа падает с panic: send on closed channel, потому что главный поток закрывает канал ch, не дождавшись завершения горутины, которая в это время пытается записать в канал. Требуется изменить поведение так, чтобы программа завершалась корректно, например, дождаться завершения горутины перед закрытием канала.

package main

import (
 "fmt"
 "time"
)

func main() {
 ch := make(chan int)

 go func() {
  ch <- 1
 }()

 time.Sleep(time.Millisecond * 500)
 close(ch)

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

 time.Sleep(time.Millisecond * 100)
}

Ответ

Пусть горутина закроет канал после отправки, а main сразу начнёт чтение. Ожидать отправителя до начала чтения небуферизированного канала нельзя.

Исправленная программа:

package main

import "fmt"

func main() {
    ch := make(chan int)
    go func() {
        defer close(ch)
        ch <- 1
    }()
    for value := range ch {
        fmt.Println(value)
    }
}

Вывод — 1. Range ждёт значение и затем закрытие канала; Sleep не нужен. В исходнике отправитель ожидает получателя, а main закрывает канал прямо во время этого ожидания, что вызывает send on closed channel, если горутина продолжает исполняться. Порядок владения важнее временных задержек.

ИИ-помощник для собеседований

Хочешь уверенно проходить собеседования?

Попробуй ИИ-помощник для собеседований: слышит вас и собеседника, анализирует экран, подсказывает ответы в реальном времени, работает без VPN и не попадает в захват экрана.

Подробнее