Reputation: 592
Let's say we are selecting on two channel. After running a few times, one of the channels is closed. How can I break out of the select?
package main
import (
"fmt"
)
func main() {
ch := make(chan int)
closed := make(chan bool, 1)
go func() {
for i := 0; i < 5; i++ {
ch <- 1
}
close(ch)
}()
for {
select {
case v := <-ch:
fmt.Printf("v is %v\n", v)
case <-closed:
fmt.Println("The server is closed!")
return
}
}
fmt.Println("Break!")
}
It is blocked infinitely. How to make it work?
Upvotes: 3
Views: 7944
Reputation: 6278
Here is working code that:
select-case
. (according to the comment from @zzn this behavior is random and it's better not to rely on this - better to check if channel has been closed). closed
channelhttps://play.golang.org/p/K83XcPbr7b
package main
import (
"fmt"
)
func main() {
ch := make(chan int)
closed := make(chan bool)
go func() {
for i := 0; i < 5; i++ {
ch <- i
}
close(ch)
closed <- true
}()
for {
select {
case <- closed:
fmt.Println("The server is closed!")
return
case v := <- ch:
fmt.Printf("v is %v\n", v)
}
}
fmt.Println("Break!")
}
If you don't change order of case there would be extra "zero" value: https://play.golang.org/p/JJaomKgqy8
Maybe it's better to check if channel has been closed?
https://play.golang.org/p/7Nd63b3JZ_
package main
import (
"fmt"
)
func main() {
ch := make(chan int)
go func() {
for i := 0; i < 5; i++ {
ch <- i
}
close(ch)
}()
for {
select {
case v, hasMore := <- ch:
if !hasMore {
return
}
fmt.Printf("v is %v\n", v)
}
}
fmt.Println("Break!")
}
Upvotes: 1
Reputation: 72241
You can return if the channel says it has no more items:
case v, more := <-ch:
if !more {
return
}
fmt.Printf("v is %v\n", v)
Upvotes: 5