> Is the select semantically different than something like this?
Yes. select can do a lot of things. It's overloaded to be something like 5 different things. Here, let me show you:
chanOne := make(chan int)
chanTwo := make(chan int)
ctx := context.Background()
// Receive whichever is ready first. Blocking
select {
case v := <-chanOne:
case v := <-chanTwo:
}
// Non-blocking read
select {
case v := <-chanOne:
default:
}
// Timeout and cancellation
select {
case v := <-chanOne:
case <-time.After(1 * time.Second):
// timeout
case <-ctx.Done():
// cancel
}
// Write or read, whichever channel is ready first
select {
case chanOne <- 1:
case v := <-chanTwo:
}
Another form of cancellation is closing channels, which causes reads to return the zero value immediately, and causes any writes to that closed channel to immediately panic (effectively abort the program).