range, направленные, nil-канал
Аня попросила сделать видимым, кто в конвейере писал, а кто читал: глядя на сигнатуру шага, было ясно, куда тёк поток файлов. Миша переписал шаги — сигнатуры указали направление, а циклы чтения сократились до простого range.
range по каналу читает до закрытия; направленные типы (chan<-, <-chan) ограничивают, кто что может делать; nil-канал блокирует обе операции навсегда.
Range до закрытия
for f := range ch {
process(f)
}
// цикл вышел — канал закрыт и опустошён
range по каналу читает значения, пока канал не закроется и не опустеет. Это идиоматичная замена ручному циклу с ok из прошлого урока — короче и без ошибки «забыл проверить ok».
Направленные типы
func produce(out chan<- File) { // шаг может только отправлять
out <- file
close(out)
}
func consume(in <-chan File) { // шаг может только принимать
for f := range in {
fmt.Println(f)
}
}
ch := make(chan File)
go produce(ch)
consume(ch)
chan<- File — только отправка, <-chan File — только приём. Компилятор следит: попытка читать из chan<- или писать в <-chan — ошибка сборки. Обычный chan File приводится к обоим направлениям автоматически. Направленные типы документируют намерение в сигнатуре: глядя на produce(out chan<- File), сразу понятно, кто пишет, а кто читает — в конвейере это и есть договор между шагами.
Nil-канал блокирует навсегда
var ch chan int // nil
ch <- 1 // блокировка навсегда
<-ch // блокировка навсегда
Кажется, что это источник вечных блокировок, но nil-канал — инструмент: в select его case можно «выключить», присвоив каналу nil. Подробнее — в уроке.
Вы узнаете:
- почему
close(chan<-)разрешён, аclose(<-chan)нет - чем
rangeотличается от ручного цикла сokпо производительности
range — чтение до закрытия; направленные типы — контроль доступа на уровне компиляции; nil-канал — вечная блокировка, полезная в select.
10 000 ₽ · 60 минут · онлайн