Ответ
Основные правила (или "аксиомы") при работе с каналами в Go, знание которых помогает избегать паник и дедлоков:
-
Отправка в закрытый канал вызывает панику.
- После
close(ch)
любая операцияch <- data
приведет кpanic: send on closed channel
.ch := make(chan int) close(ch) ch <- 1 // panic: send on closed channel
- После
-
Чтение из закрытого канала никогда не блокируется.
- Вместо блокировки операция чтения немедленно возвращает нулевое значение для типа данных канала. Вторая переменная в
v, ok := <-ch
будетfalse
, что позволяет определить, был ли канал закрыт. - Это свойство обеспечивает корректное завершение циклов
for range
по каналу.ch := make(chan int, 1) ch <- 42 close(ch) v, ok := <-ch // v = 42, ok = true v, ok = <-ch // v = 0, ok = false
- Вместо блокировки операция чтения немедленно возвращает нулевое значение для типа данных канала. Вторая переменная в
-
Закрытие уже закрытого канала вызывает панику.
close(ch)
можно вызывать только один раз.ch := make(chan int) close(ch) close(ch) // panic: close of closed channel
-
Отправка в
nil
-канал блокируется навсегда.var ch chan int // ch == nil ch <- 1 // deadlock
-
Чтение из
nil
-канала блокируется навсегда.- Это свойство (вместе с предыдущим) является полезным идиоматическим приемом. В операторе
select
можно присвоить каналуnil
, чтобы временно "отключить" соответствующийcase
.var ch chan int // ch == nil <-ch // deadlock
- Это свойство (вместе с предыдущим) является полезным идиоматическим приемом. В операторе
-
Закрытие
nil
-канала вызывает панику.var ch chan int // ch == nil close(ch) // panic: close of nil channel