Ответ
Операции чтения и записи в nil-канал блокируют исполнение горутины навсегда.
Если в программе не останется других активных горутин, среда выполнения Go прервет программу с ошибкой fatal error: all goroutines are asleep - deadlock!.
Поведение при операциях:
-
Запись в
nil-каналvar ch chan int // ch == nil ch <- 42 // Эта горутина заблокируется здесь навсегда -
Чтение из
nil-каналаvar ch chan int // ch == nil <-ch // Эта горутина также заблокируется навсегда
Практическое применение
Это предсказуемое поведение часто используется в операторе select для динамического включения или отключения одного из case. Если канал в case равен nil, этот case никогда не будет выбран.
var ch1, ch2 chan int
// ...
// Чтобы временно отключить обработку из ch2, можно сделать так:
// ch2 = nil
select {
case val := <-ch1:
fmt.Println("Получено из ch1:", val)
case val := <-ch2: // Этот case будет игнорироваться, если ch2 == nil
fmt.Println("Получено из ch2:", val)
} Ответ 18+ 🔞
Да ты посмотри, что вытворяют с этими каналами! Ну, блядь, классика жанра, ёпта.
Вот представь, объявляешь ты канал, а он nil, сука. Ну, просто переменная, пустота, нихуя. И если ты, такой довольный, попробуешь в эту пустоту что-то запихнуть — ch <- 42 — всё, пиши пропало. Горутина твоя встанет как вкопанная и будет ждать у моря погоды. До скончания века, блядь. Пока её кто-нибудь не разбудит. А если никто не разбудит, потому что все остальные тоже уснули, то программа твоя охуеет и сдохнет с криком fatal error: all goroutines are asleep - deadlock!. Красиво, да?
То же самое и с чтением. Пытаешься вытащить что-то из ниоткуда — <-ch — и опять впадаешь в вечную спячку. Охуенная ловушка для новичков, ядрёна вошь!
var ch chan int // ch == nil, пустота, пиздец
ch <- 42 // Всё, приехали. Сиди тут и жди. Бесконечно.
Но, блядь, гении, которые Go придумывали, они же не просто так это сделали! Они знали, что на этом можно сыграть. Особенно в этом вашем select, хитрая жопа.
Смотри, есть у тебя два канала, ch1 и ch2. И ты в select их слушаешь. А потом тебе надо, чтобы ch2 на время заткнулся, не мешался. Ну, ты можешь его, мудака, в nil превратить! И что происходит? А в select case с nil-каналом никогда не сработает, его как будто и нет! Удобно же, в рот меня чих-пых!
var ch1, ch2 chan int
// ...
// Хочу, чтобы ch2 не работал
// ch2 = nil // Вот и вся магия, ёбана!
select {
case val := <-ch1:
fmt.Println("Получено из ch1:", val)
case val := <-ch2: // А этот case теперь спит, как сурок, потому что ch2 — нихуя
fmt.Println("Получено из ch2:", val) // Сюда мы никогда не попадём, пока ch2 nil
}
Вот так вот, блядь. Казалось бы, баг, а оказалось — фича. Главное — не наступить на эти грабли в обычном коде, а то охуеешь потом искать, где же твоя горутина сгинула.