Nil-канал — это канал, который объявлен, но не инициализирован с помощью make()
. В Go канал является ссылочным типом, поэтому его нулевое значение — nil
.
var ch chan int // ch == nil
Навсегда блокирует горутину (deadlock):
var ch chan int
ch <- 42 // fatal error: all goroutines are asleep - deadlock!
Навсегда блокирует горутину (deadlock):
var ch chan int
val := <-ch // fatal error: all goroutines are asleep - deadlock!
Вызывает panic:
var ch chan int
close(ch) // panic: close of nil channel
Дизайн языка Go:
Отличие от других nil-типов:
chInitialized := make(chan int) // работает
var chNil chan int // deadlock при использовании
var chNil chan int
select {
case <-chNil: // этот case никогда не сработает
fmt.Println("Read from nil channel")
case <-time.After(time.Second):
fmt.Println("Timeout") // сработает это
}
Nil-каналы иногда используют для "отключения" case в select:
var ch chan int // nil
select {
case v := <-ch: // блокируется, но не deadlock в select
fmt.Println(v)
default:
fmt.Println("Default case")
}
var activeChan chan int
if condition {
activeChan = make(chan int, 1)
activeChan <- 1
}
select {
case v := <-activeChan: // если condition=false, case игнорируется
fmt.Println(v)
}
ch := make(chan int) // вместо var ch chan int
if ch != nil {
ch <- value
}
func NewChannel() chan int {
return make(chan int)
}
Понимание поведения nil-каналов помогает избежать тонких ошибок в конкурентном коде на Go.