Читаем через Concurrency in Go
и вводим удобный "или готовый" канал.
TLDR; когда вы работаете с каналом, которым вы не управляете (предположительно из какой-то другой части вашей системы), код может стать немного уродливым.
// Quite nice to read
for v := range myChan {
... Do Stuff
}
// Not so nice
loop:
for {
select {
case <- done:
break loop
case maybeVal, ok := <-myChan:
if !ok {
return
}
// Do something with maybeVal
}
}
Книга предлагает способ упростить это с помощью канала OrDone. Определяется следующим образом. Что я не понимаю, так это то, почему во вложенном выборе нужно снова получать от <-done. </p>
orDone := func(done, c <-chan interface{}) <-chan interface{} {
valStream := make(chan interface{})
go func() {
defer close(valStream)
for {
select {
case <- done:
return
case v, ok := <-c:
if !ok {
return
}
select {
case valStream <- v:
case <-done: // Why do we also need to receive on done here?
}
}
}
}
return valStream
}
Это позволяет вам go вернуться к вашему оригиналу для l oop, улучшение читабельности - вот так:
for val := range orDone(done, myChan) {
// Once again, do something
}