Look at the following code snippet
package main
import (
"fmt"
"time"
)
func sender(ch chan string) {
ch <- "Hello"
ch <- "Foo"
ch <- "and"
ch <- "Boo"
close(ch)
}
func main() {
ch := make(chan string)
go sender(ch)
for {
select {
case value := <-ch:
fmt.Println(value)
case <-time.After(time.Second * 2):
fmt.Println("Return")
return
}
}
}
As result I've got blank output and the time.After will be never reached. Why?
I notice, when I try to receive value from a closed channel, it will receive the zero value from the type. Why can I still receive value from a closed channel?
I can check also like is too,
v, ok := <-ch
if ok is false, the channel is closed.
A new two second timer is created on every iteration of the for loop. Closed channels are always ready to receive. The code loops forever because the channel for the new timer is never ready to receive before the closed channel is ready to receive.
One way to fix the problem is to set the channel to nil:
case value, ok := <-ch:
if !ok {
ch = nil
} else {
fmt.Println(value)
}
Receive on a nil channel is never ready.
If you wanted the loop to run for at most two seconds, then you should create the timer outside of the loop:
after := time.After(time.Second * 2)
and select on this one timer in the loop:
case <-after:
fmt.Println("Return")
return
playground example (sleep added to make example run on playground)
You can combine setting the channel to nil and creating the timer outside of the loop.