6

在玩 Go 的频道和例程时,我遇到了一种奇怪的行为,我希望有人能解释一下。

下面是一个简短的程序,它应该通过通道将字符串发送到在单独的 goroutine 中运行的“侦听器”(select 语句),从而将几个字符串打印到标准输出。

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

即只打印所有其他语句。这是什么魔法?

4

3 回答 3

12

在最上面的代码片段中,您从每个循环的通道中提取两个值。一个在 select 语句中,一个在 print 语句中。

改变

        select {
        case <-a:
            fmt.Print(<-a)

        select {
        case val := <-a:
            fmt.Print(val)

http://play.golang.org/p/KIADcwkoKs

于 2013-03-23T22:32:15.057 回答
7
<-a

破坏性地从通道中获取值。因此,在您的代码中,您会得到两个值,一个在 select 语句中,一个用于打印。在 select 语句中收到的那个没有绑定到任何变量,因此会丢失。

尝试

select {
    case val := <-a:
        fmt.Print(val)

相反,要仅获取一个值,请将其绑定到变量 val,然后将其打印出来。

于 2013-03-23T22:33:58.913 回答
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) 
}
于 2019-09-06T10:06:05.897 回答