Напиши функцию на Go, которая принимает слайс каналов int и возвращает канал с суммами чисел из каждого канала
Что проверяют
Знаете ли вы шаблон fan-in и понимаете ли, что вернуть канал означает вернуть его сразу, а считать в фоне. Попутно смотрят на типы: направленные каналы в сигнатуре сразу показывают, кто читатель, а кто писатель.
Как отвечать
По горутине на входной канал, общий выходной канал, закрытие после ожидания:
func SumChannels(chans []<-chan int) <-chan int {
out := make(chan int, len(chans))
var wg sync.WaitGroup
wg.Add(len(chans))
for _, ch := range chans {
go func(ch <-chan int) {
defer wg.Done()
sum := 0
for n := range ch {
sum += n
}
out <- sum
}(ch)
}
go func() {
wg.Wait()
close(out)
}()
return out
}Разберите вслух по шагам: функция не блокируется, потому что вся работа в горутинах; вызывающий читает результат через range и выходит, когда канал закрыт; закрывать out нужно из отдельной горутины после wg.Wait(), иначе либо закроем рано, либо заблокируем возврат. Буфер размером в число каналов даёт горутинам завершиться, даже если читатель задержался. Если нужен порядок сумм, совпадающий с порядком каналов, канал не подходит: пишите в слайс по индексу и отдавайте его после ожидания.
Где спотыкаются
Считают суммы последовательно в одной горутине. Формально работает, но смысл задачи теряется: один медленный канал задерживает все остальные, а спрашивали именно про конкурентность.
Второе: закрывают выходной канал в той же горутине, которая в него пишет, либо не закрывают совсем. В первом случае возможна запись в закрытый канал и паника, во втором читатель повисает навсегда.
Третье: захват переменной цикла. Начиная с Go 1.22 переменная своя на каждой итерации, но в коде постарше горутины без передачи ch параметром соберутся все на последнем канале. Про эту разницу спрашивают почти всегда.