6

Goのチャンネルやルーティンをいじってみて、誰かが説明してくれることを望んでいた独特の振る舞いに出くわしました。

以下は、別のゴルーチンで実行されている「リスナー」(selectステートメント)にチャネルを介して文字列を送信することにより、stdoutにいくつかの文字列を出力することになっている短いプログラムです。

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

一番上のスニペットでは、ループごとにチャネルから2つの値を取得しています。1つはselectステートメントに、もう1つは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

破壊的にチャネルから値を取得します。したがって、コードでは2つの値を取得します。1つはselectステートメントにあり、もう1つは印刷に使用します。selectステートメントで受け取ったものはどの変数にもバインドされていないため、失われます。

試す

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

代わりに、値を1つだけ取得するには、それを変数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 に答える