Попытка записи в закрытый канал вызывает панику (panic) в runtime. Это одно из ключевых отличий от чтения из закрытого канала, которое является безопасной операцией.
ch := make(chan int)
close(ch)
ch <- 42 // panic: send on closed channel
runtime error: send on closed channel
ch := make(chan int)
close(ch)
ch <- 1 // Всегда паника
ch := make(chan int, 1)
close(ch)
ch <- 1 // Паника, даже если есть место в буфере
select {
case ch <- data:
// Успешная запись
default:
// Канал заблокирован (полон или закрыт)
}
var once sync.Once
closeCh := make(chan struct{})
// Где-то в коде:
once.Do(func() { close(closeCh) }) // Гарантирует однократное закрытие
var (
dataCh = make(chan int)
isClosed bool
mu sync.Mutex
)
func safeSend(v int) bool {
mu.Lock()
defer mu.Unlock()
if isClosed {
return false
}
select {
case dataCh <- v:
return true
default:
return false
}
}
Хотя лучше избегать записи в закрытый канал, можно обработать панику:
func safeChannelSend(ch chan<- int, value int) (err error) {
defer func() {
if r := recover(); r != nil {
err = fmt.Errorf("channel send panic: %v", r)
}
}()
ch <- value
return nil
}
Операция | Закрытый канал | Незакрытый канал |
---|---|---|
Чтение (<-ch ) |
Возвращает zero-value | Блокирует/возвращает данные |
Запись (ch<- ) |
Паника | Блокирует/передает данные |
запись в закрытый канал в Go всегда вызывает панику, независимо от типа канала (буферизованный/небуферизованный). Это осознанное решение языка для предотвращения скрытых ошибок. Всегда проектируйте свою программу так, чтобы избегать подобных ситуаций, используя правильные шаблоны работы с каналами и синхронизацию.