select без default блокируется, пока хотя бы один из каналов не будет готов к операции. С default ветка default выполняется сразу, если ни один канал не готов - получается неблокирующее чтение или запись.
select {
case v := <-ch:
use(v)
default:
// ch не готов - не ждём, идём сюда
return nil, ErrNoData
}
select {
case ch <- value:
// отправили
default:
// канал полон или закрыт - не блокируемся
}
Без default горутина могла бы навсегда заблокироваться на одном из case. default даёт возможность обработать "ни один канал не готов" и выйти или повторить позже.