Default Selection

Add a default case to a select and it becomes non-blocking. If none of the channel cases are ready, default runs immediately instead of blocking.

select {
case i := <-c:
	// use i
default:
	// receiving from c would block
}

This is the pattern for “try to communicate, but don’t wait.” It’s useful for polling or checking channel state without getting stuck.

Try it: watch the output — the default case fires repeatedly (printing .) while the goroutine waits between ticks and the final boom.

package main

import (
	"fmt"
	"time"
)

func main() {
	start := time.Now()
	tick := time.Tick(100 * time.Millisecond)
	boom := time.After(500 * time.Millisecond)
	elapsed := func() time.Duration {
		return time.Since(start).Round(time.Millisecond)
	}
	for {
		select {
		case <-tick:
			fmt.Printf("[%6s] tick.\n", elapsed())
		case <-boom:
			fmt.Printf("[%6s] BOOM!\n", elapsed())
			return
		default:
			fmt.Printf("[%6s]     .\n", elapsed())
			time.Sleep(50 * time.Millisecond)
		}
	}
}