チャネルの状態には、オープンとクローズ(closed)の状態があり、make
することで生成された チャネル はオープンな状態となり、close(チャネル)
で明示的に閉じることができます。
チャネル が close されたことを複数のゴルーチン (goroutine) へ一斉に伝えることができますので、close
関数を使ってブロードキャストによるキャンセル処理を実装できます。
なお、この手の処理は今はコンテキスト処理を使って行う方がよいのだと思います。ただ、この素の状態でのやり方も見ておいて損はないでしょう。。
以下は状況把握のためのサンプルになります。
3つのバッファをもつ int 型の チャネル を作成し、値を3つ送信した後に直ぐにクローズします。
case i, more := <-ch:
については補足します。
チャネル を受信する際に戻り値に2つの変数を用意すると、1つ目(i
)にはその値、2つ目(more
)にはチャネルのオープン状態の真偽値(true/false
)が入ってきます。
以下はチャネルを受信する際のイディオム for
ループ、select
の構文となっていますが、select
でチャネルを受信後、そのチャネルのオープン状態(more
)をチェックすることで処理の終了(ループの終了)を判断しています。
package main import "fmt" func main() { ch := make(chan int, 3) ch <- 1 ch <- 2 ch <- 3 close(ch) for { select { case i, more := <-ch: if more { fmt.Printf("OpenStatus: %v, value: %d\n", more, i) } else { fmt.Printf("OpenStatus: %v, value: %d\n", more, i) fmt.Println("exit for loop") goto L } } } L: fmt.Println("Finish!") }
上記の実行結果は以下の通りです。
OpenStatus: true, value: 1 OpenStatus: true, value: 2 OpenStatus: true, value: 3 OpenStatus: false, value: 0 exit for loop Finish!
この結果からわかることとしまして、
- チャネルはクローズされていても、また、バッファ内が空になっていても受信は行える。
- チャネルのバッファが空で、かつ、クローズされた状態の場合に、チャネルのオープン状態を保持する変数(
more
)はfalse
になる。
この結果からもチャネルのオープン状態を保持する変数(more
)は確実にチャネルのバッファ内にある値をもれなく取り出せることを保証していますので、上記のような最後まで取り出して完了、という判断に利用できます。