玩Go的频道和惯例我遇到了一种特殊的行为,我希望有人可以解释。
下面是一个简短的程序,它应该通过一个通道将字符串发送给一个"监听器"来将一些字符串打印到stdout。 (select语句)在单独的goroutine中运行。
package main
import (
"fmt"
"time"
)
func main() {
a := make(chan string)
go func() {
for {
select {
case <-a:
fmt.Print(<-a)
}
}
}()
a <- "Hello1\n"
a <- "Hello2\n"
a <- "Hello3\n"
a <- "Hello4\n"
time.Sleep(time.Second)
}
使用
go func() {
for s := range a {
fmt.Print(s)
}
}()
// or even simpler
go func() {
for {
fmt.Print(<-a)
}
}()
按预期工作。但是,使用select语句运行最上面的代码段会产生以下输出:
Hello2
Hello4
即。只打印其他所有声明。这是什么样的巫术?
答案 0 :(得分:12)
在最上面的代码段中,您为每个循环从通道中提取两个值。一个在select语句中,一个在print语句中。
更改
select {
case <-a:
fmt.Print(<-a)
要
select {
case val := <-a:
fmt.Print(val)
答案 1 :(得分:7)
<-a
破坏性地从频道中获取值。因此,在您的代码中,您将获得两个值,一个在select语句中,另一个用于打印。在select语句中收到的那个没有绑定到任何变量,因此丢失了。
尝试
select {
case val := <-a:
fmt.Print(val)
相反,只获取一个值,将其绑定到变量val,然后将其打印出来。
答案 2 :(得分:0)
package main
import (
"fmt"
"time"
)
func main() {
a := make(chan string)
go func() {
for {
select {
case v:= <-a:
fmt.Print(v)
}
}
}()
a <- "Hello1\n"
a <- "Hello2\n"
a <- "Hello3\n"
a <- "Hello4\n"
time.Sleep(5*time.Second)
}