英文:
Why never reached the return statement
问题
请注意以下代码片段:
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
}
}
}
作为结果,我得到了空白输出,并且 time.After
永远不会被触发。为什么会这样?
我注意到,当我尝试从一个已关闭的通道接收值时,它会接收到该类型的零值。为什么我仍然可以从一个已关闭的通道接收值?
我还可以像这样进行检查:
v, ok := <-ch
如果 ok
为 false
,则表示通道已关闭。
英文:
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.
答案1
得分: 4
在每次for循环迭代时,都会创建一个新的两秒计时器。关闭的通道始终准备好接收。代码会一直循环,因为在关闭的通道准备好接收之前,新计时器的通道永远不会准备好接收。
修复问题的一种方法是将通道设置为nil:
case value, ok := <-ch:
if !ok {
ch = nil
} else {
fmt.Println(value)
}
对于nil通道的接收永远不会准备好。
如果你希望循环最多运行两秒钟,那么你应该在循环外创建计时器:
after := time.After(time.Second * 2)
并在循环中选择这个计时器:
case <-after:
fmt.Println("Return")
return
playground示例(添加了sleep以在playground上运行示例)
你可以将将通道设置为nil和在循环外创建计时器结合起来。
英文:
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.
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论