Ответ
Да, читать из закрытого канала можно. Эта операция никогда не блокируется и не вызывает панику. Поведение зависит от способа чтения:
-
С использованием второй переменной
ok: Это идиоматический способ проверки, закрыт ли канал. Чтение из закрытого канала немедленно вернет нулевое значение для типа данных канала иfalseдля переменнойok.ch := make(chan int, 1) ch <- 10 close(ch) val, ok := <-ch // val = 10, ok = true (сначала читаем оставшиеся данные) val, ok = <-ch // val = 0, ok = false (канал пуст и закрыт) -
В цикле
for range: Циклfor rangeавтоматически прекратит свою работу, когда канал будет закрыт и все значения из него будут прочитаны.ch := make(chan int, 2) ch <- 1 ch <- 2 close(ch) // Цикл напечатает 1 и 2, а затем завершится for v := range ch { fmt.Println(v) } -
Без проверки
ok: Если не использовать вторую переменную, вы будете бесконечно получать нулевые значения, что может привести к ошибкам в логике. Поэтому всегда проверяйте статус канала при чтении.
Ответ 18+ 🔞
А, ну вот, смотри, с каналами-то какая история. Читать из закрытого — можно, блядь, это ж не паника. Никогда не паникует, операция такая. А вот что вернёт — это уже зависит от того, как ты читаешь, хитрая жопа.
Вот смотри, три варианта, как это бывает:
Первый, самый правильный, с проверкой ok. Это типа идиома такая, стандартная. Ты как бы спрашиваешь: «Э, канал, ты ещё живой, или уже всё?». Если канал закрыт и в нём пусто, то тебе вернётся ноль для типа (0 для int, "" для string, nil для указателей) и false в эту самую ok. Всё честно.
ch := make(chan int, 1)
ch <- 10
close(ch)
val, ok := <-ch // val = 10, ok = true (ну, данные же ещё были, ёпта!)
val, ok = <-ch // val = 0, ok = false (всё, писец, канал пустой и закрыт. Дальше только нули)
Второй, через for range. Вообще красота, блядь. Самый удобный способ. Цикл этот умный, он сам поймёт, когда канал закрыли и всё вычитали, и тихо, мирно завершится. Не надо там никаких ok ловить.
ch := make(chan int, 2)
ch <- 1
ch <- 2
close(ch)
// Цикл напечатает 1 и 2, а потом просто выйдет, потому что понял — всё, кончилось.
for v := range ch {
fmt.Println(v)
}
А третий вариант — это просто тупо читать без проверки. Вот это, блядь, мартышлюшка. Ты будешь как дурак бесконечно получать нулевые значения после закрытия, и программа твоя может сойти с ума, потому что логика поедет. Поэтому, ёпта, всегда проверяй, жив канал или уже приказал долго жить. Не будь как этот Герасим, который нихуя не говорил, пока Муму не утопил.