В чем разница между чтением из закрытого и nil-канала в Go?

Ответ

Поведение при чтении из закрытого и nil-канала кардинально отличается и является важной концепцией для понимания конкурентности в Go.

Чтение из закрытого канала

Чтение из закрытого канала никогда не блокируется. Оно немедленно возвращает два значения:

  1. Zero-value для типа данных канала.
  2. false в качестве второго параметра (ok).

Это позволяет надежно определить, что канал был закрыт и больше не будет поставлять данные.

ch := make(chan int, 1)
ch <- 100
close(ch)

val, ok := <-ch // val = 100, ok = true (читаем последнее значение)
val, ok = <-ch // val = 0,   ok = false (канал пуст и закрыт)
val, ok = <-ch // val = 0,   ok = false (можно читать бесконечно)

Чтение из nil-канала

Канал является nil, если он был объявлен, но не инициализирован с помощью make().

Чтение из nil-канала блокирует горутину навсегда. Это приводит к deadlock, если ни одна другая горутина не сможет записать в этот канал (что невозможно, так как он nil).

var ch chan int // ch == nil

// Эта операция заблокирует текущую горутину навсегда
// и программа упадет с паникой deadlock
<-ch 

Сводная таблица поведения

ОперацияЗакрытый каналnil-канал
Чтение (<-ch)Немедленно возвращает (zero-value, false)Блокирует навсегда (deadlock)
Запись (ch <- val)Паника (panic)Блокирует навсегда (deadlock)
Закрытие (close(ch))Паника (panic on second close)Паника (panic)