概要
頻繁に使うことはありませんが、知っておくといざというときに便利かもしれません。
N個のチャネルを持っていて、その中のどれでもいいので値を受信したいってときがたまにあります。
そのような場合、reflectパッケージを使って処理すると動的な数のチャネルに対応できるときがあります。
サンプルを見たほうが早いと思いますので、以下に記載
サンプル
package reflectop import ( "reflect" "github.com/devlights/gomy/output" ) // SelectCase -- reflect.SelectCase のサンプルです。 // // REFERENCES: // - https://dev.to/hgsgtk/handling-with-arbitrary-channels-by-reflectselect-4d5g func SelectCase() error { // 複数のチャネルを持っていて、その中のどれかのチャネルからでも良いので // データを取得していきたい場合、通常は for-select を使って処理することになる。 // ただし、その場合、必要な分だけ case を増やしていかないと行けない. // // reflect.Select() を利用することで、リフレクションを利用して処理することが出来る const ( chCount = 5 ) // チャネルを5つ用意 chs := make([]chan int, chCount) for i := 0; i < chCount; i++ { ch := make(chan int) go func(i int) { ch <- i * i }(i) chs[i] = ch } // reflect.SelectCase を用意 scs := make([]reflect.SelectCase, len(chs)) for i, ch := range chs { sc := reflect.SelectCase{ Dir: reflect.SelectRecv, Chan: reflect.ValueOf(ch), } scs[i] = sc } // リフレクションを使って、複数のチャネルから一つ値を取得 for i := 0; i < chCount; i++ { chosen, recv, ok := reflect.Select(scs) if ok { output.Stdoutf("reflect.Select", "chosen: %v\trecv: %v\n", chosen, recv) } } // 使ったチャネルを閉じる(このプログラムでは必要ないけど、お作法として) for _, ch := range chs { close(ch) } return nil }
試してみる
実行すると以下のようになります。
gitpod /workspace/try-golang $ make run go run github.com/devlights/try-golang/cmd/trygolang -onetime -example "" ENTER EXAMPLE NAME: reflect_selectcase [Name] "reflect_selectcase" reflect.Select chosen: 4 recv: 16 reflect.Select chosen: 3 recv: 9 reflect.Select chosen: 0 recv: 0 reflect.Select chosen: 1 recv: 1 reflect.Select chosen: 2 recv: 4 [Elapsed] 230.465µs
reflect.Select
するたびにどれか一つのチャネルから値が取得出来ていますね。
参考情報
過去の記事については、以下のページからご参照下さい。
- いろいろ備忘録日記まとめ
サンプルコードは、以下の場所で公開しています。
- いろいろ備忘録日記サンプルソース置き場