Go Select
A select statement is a block that waits on several channel operations at once. It runs one ready case and then moves on.
One ready case runs
A ready case is a case whose channel operation can move ahead now. This channel already holds a value, so the receive case is ready.
package main
import "fmt"
func main() {
ch := make(chan string, 1)
ch <- "First report"
select {
case report := <-ch:
fmt.Println(report)
}
}The default case runs when nothing is ready
The default case runs when no other case is ready. This channel has no sender, so no receive can move ahead.
package main
import "fmt"
func main() {
ch := make(chan string)
select {
case report := <-ch:
fmt.Println(report)
default:
fmt.Println("No report yet")
}
}Only one of two channels sends
Two receive cases wait in this select. Only the first channel ever sends a value, so only its case can become ready.
package main
import "fmt"
func main() {
first := make(chan string, 1)
first <- "Harbor report"
second := make(chan string)
select {
case report := <-first:
fmt.Println(report)
case report := <-second:
fmt.Println(report)
}
}A select loop drains a closed channel
The ok value reports whether a receive took a real value. It turns false after the channel closes and empties, and the loop stops there.
package main
import "fmt"
func main() {
ch := make(chan int, 3)
ch <- 7
ch <- 14
ch <- 21
close(ch)
for {
select {
case value, ok := <-ch:
if !ok {
fmt.Println("Feed closed")
return
}
fmt.Println(value)
}
}
}Example
package main
import "fmt"
func publish(feed chan<- string) {
feed <- "Storm clears"
feed <- "Roads reopen"
feed <- "Trains run again"
}
func main() {
active := make(chan string)
silent := make(chan string)
go publish(active)
for round := 0; round < 3; round++ {
select {
case report := <-active:
fmt.Println(report)
case report := <-silent:
fmt.Println(report)
}
}
}Key points
- A select block waits for one of its channel cases to become ready.
- A ready case is a case whose send or receive can move ahead now.
- The default case runs when no case is ready.
- A select with no ready case and no default waits.
- Go chooses at random when two cases are ready at the same time.
- A receive from a closed channel is ready at once.
In this example, publish sends three headlines into the active channel one at a time. Main makes an active channel and a silent channel and starts publish as a goroutine. The loop runs three rounds of select. The silent channel never sends, so the active case is the only ready case each round. The three headlines print in send order.
Note
A timeout case can set a limit on a wait, and a later lesson covers that shape.
Try it Yourself
Edit the code, then press Run.
Running is simulated ยท Go Playground
Exercise
When does the default case run?