Что значит стрелочка справа у канала в Go?
Что проверяют
Читаете ли вы сигнатуры с каналами и понимаете ли, зачем в Go вообще существуют направленные типы каналов. Вопрос простой, но по ответу видно, писали ли вы конкурентный код или только читали про горутины.
Как отвечать
Стрелка в типе показывает, куда текут данные. Запись chan<- int, стрелка справа от слова chan, это канал только для отправки: в него можно писать и его можно закрыть, читать нельзя. Запись <-chan int, стрелка слева, это канал только для чтения.
Мнемоника: стрелка всегда направлена от источника к приёмнику. В chan<- данные идут в канал, в <-chan из канала.
func producer(out chan<- int) {
for i := 0; i < 3; i++ {
out <- i
}
close(out)
}
func consumer(in <-chan int) {
for v := range in {
fmt.Println(v)
}
}Функция make(chan int) создаёт двусторонний канал, и при передаче в функцию он сам приводится к нужному направленному типу. Обратное приведение запрещено, в этом и смысл: направление зафиксировано в сигнатуре, компилятор не даст потребителю случайно записать в канал или закрыть его, а читателю сигнатуры видно, кто здесь пишет.
Не путайте тип и операцию: в ch <- v стрелка это оператор отправки, v := <-ch приём, а v, ok := <-ch дополнительно сообщает, открыт ли ещё канал.
Где спотыкаются
Пробуют закрыть канал на стороне читателя. Вызов close для <-chan не компилируется, и это правильный дизайн: закрывает тот, кто пишет, иначе отправка в закрытый канал даёт панику.
Второе: объявляют направленный канал переменной, вроде var ch chan<- int = make(chan int). Формально законно, но бесполезно: второй конец потерян, и запись заблокируется навсегда. Направление задают в параметрах функций.
Третье: приписывают направлению влияние на поведение канала. Чтение из закрытого канала сразу отдаёт нулевое значение, а любая операция с каналом, равным nil, блокируется навсегда, и направленность тут ни при чём.