Go言語のselect文

Go 语言条件语句Go言語の条件文

select は Go における制御構造の一つで、switch文に似ています。

select文はチャネル操作にのみ使用でき、各caseはチャネル操作(送信または受信)でなければなりません。

select文は指定されたすべてのチャネル上の操作を監視し、いずれかのチャネルが準備でき次第、対応するコードブロックを実行します。

複数のチャネルが準備できている場合、select文はランダムに1つのチャネルを選んで実行します。すべてのチャネルが準備できていない場合は、defaultブロックのコードを実行します。

構文

Goプログラミング言語におけるselect文の構文は次のとおりです。


select {
  case <- channel1:
    // 実行するコード
  case value := <- channel2:
    // 実行するコード
  case channel3 <- value:
    // 実行するコード

    // caseは任意の数だけ定義できます

  default:
    // すべてのチャネルが準備できていない場合に実行するコード
}

以下にselect文の構文を示します。

  • 各caseはチャネルでなければなりません
  • すべてのchannel式が評価されます
  • 送信されるすべての式が評価されます
  • 任意のチャネルが実行可能であれば、それが実行され、他は無視されます。
  • 複数のcaseが実行可能な場合、selectはランダムかつ公平に1つを選んで実行し、他は実行されません。
    そうでない場合:
    1. default句があれば、その文を実行します。
    2. default句がない場合、selectはいずれかのチャネルが実行可能になるまでブロックします。Goはchannelや値を再評価しません。

実例

select文の適用デモ:

実例

package main

import (
    "fmt"
    "time"
)

func main() {

    c1 := make(chan string)
    c2 := make(chan string)

    go func() {
        time.Sleep(1 * time.Second)
        c1 <- "one"
    }()
    go func() {
        time.Sleep(2 * time.Second)
        c2 <- "two"
    }()

    for i := 0; i < 2; i++ {
        select {
        case msg1 := <-c1:
            fmt.Println("received", msg1)
        case msg2 := <-c2:
            fmt.Println("received", msg2)
        }
    }
}

上記のコードの実行結果は次のとおりです。

received one
received two

上記の例では、2つのチャネルc1とc2を作成しました。

select文は2つのチャネルのデータを待ちます。c1のデータを受信すると "received one" を出力し、c2のデータを受信すると "received two" を出力します。

次の例では、2つのチャネルを定義し、2つのコルーチン(Goroutine)を起動してこれらのチャネルからデータを取得します。main関数では、select文を使用してこれら2つのチャネルに対してノンブロッキングな選択を行い、両方のチャネルに利用可能なデータがない場合はdefault句の文を実行します。

次の例を実行すると、2つのチャネルからデータを取得し続け、両方のチャネルに利用可能なデータがない場合は "no message received" と出力します。

実例

package main

import "fmt"

func main() {
  // 2つのチャネルを定義
  ch1 := make(chan string)
  ch2 := make(chan string)

  // 2つのgoroutineを起動し、それぞれのチャネルからデータを取得
  go func() {
    for {
      ch1 <- "from 1"
    }
  }()
  go func() {
    for {
      ch2 <- "from 2"
    }
  }()

  // select文を使用して2つのチャネルからノンブロッキングでデータを取得
  for {
    select {
    case msg1 := <-ch1:
      fmt.Println(msg1)
    case msg2 := <-ch2:
      fmt.Println(msg2)
    default:
      // 両方のチャネルに利用可能なデータがない場合は、ここにある文を実行
      fmt.Println("no message received")
    }
  }
}

Go 语言条件语句Go言語の条件文

その他の拡張