概要
チャネル関数の続き。( #関連記事 参照)
書籍には記載されていないですが、チャネルさんが触ってて面白いので、ネタ的な関数をこれから数回分続けようかなと。
まず、ループする用のチャネルつくる関数です。普通に回した方がいいと思いますが、勉強としてメモメモ。。
パイプラインにつなぐことができるので、これはこれで便利かもしれませんね。
サンプル
package chans import ( "math" "github.com/devlights/gomy/enumerable" ) // Loop -- 指定された開始と終了の間、データを返し続けるチャネルを生成します。 func Loop(done <-chan struct{}, start, end int) <-chan int { out := make(chan int) go func(done <-chan struct{}, start, end int) { defer close(out) fn := func() func() interface{} { r := enumerable.NewRange(start, end) return func() interface{} { defer r.Next() return r.Current() } }() repeatCh := RepeatFn(done, fn) takeCh := Take(done, repeatCh, end-start) for v := range takeCh { if i, ok := v.(int); ok { out <- i } } }(done, start, end) return out } // LoopInfinite -- 無限にループして、データを返し続けるチャネルを生成します。 func LoopInfinite(done <-chan struct{}) <-chan int { return Loop(done, 0, math.MaxInt64) }
gomy/loop.go at master · devlights/gomy · GitHub
以下テストコードです。
package chans import ( "context" "reflect" "testing" "time" ) func TestLoop(t *testing.T) { type ( testin struct { start, end int } testout struct { result []int } testcase struct { in testin out testout } ) cases := []testcase{ { in: testin{ start: 0, end: 1, }, out: testout{result: []int{0}}, }, { in: testin{ start: 0, end: 5, }, out: testout{result: []int{0, 1, 2, 3, 4}}, }, } for i, c := range cases { func() { done := make(chan struct{}) defer close(done) r := make([]int, 0, 0) for v := range Loop(done, c.in.start, c.in.end) { t.Logf("[test-%02d] %v", i, v) r = append(r, v) } if !reflect.DeepEqual(c.out.result, r) { t.Errorf("want: %v\tgot: %v", c.out.result, r) } }() } } func TestLoopInfinite(t *testing.T) { type ( testin struct { timeLimit time.Duration } testout struct { } testcase struct { in testin out testout } ) cases := []testcase{ { in: testin{timeLimit: 1 * time.Second}, out: testout{}, }, } for i, c := range cases { func() { mainCtx, cancel := context.WithTimeout(context.Background(), c.in.timeLimit) defer cancel() r := make([]int, 0, 0) for v := range LoopInfinite(mainCtx.Done()) { t.Logf("[test-%02d] %v", i, v) r = append(r, v) <-time.After(100 * time.Millisecond) } if len(r) == 0 { t.Error("want: non-zero list\tgot zero list") } }() } }
実行すると以下のようになります。
$ go test -v github.com/devlights/gomy/chans -run ^TestLoop.*$ === RUN TestLoop TestLoop: loop_test.go:48: [test-00] 0 TestLoop: loop_test.go:48: [test-01] 0 TestLoop: loop_test.go:48: [test-01] 1 TestLoop: loop_test.go:48: [test-01] 2 TestLoop: loop_test.go:48: [test-01] 3 TestLoop: loop_test.go:48: [test-01] 4 --- PASS: TestLoop (0.00s) === RUN TestLoopInfinite TestLoopInfinite: loop_test.go:86: [test-00] 0 TestLoopInfinite: loop_test.go:86: [test-00] 1 TestLoopInfinite: loop_test.go:86: [test-00] 2 TestLoopInfinite: loop_test.go:86: [test-00] 3 TestLoopInfinite: loop_test.go:86: [test-00] 4 TestLoopInfinite: loop_test.go:86: [test-00] 5 TestLoopInfinite: loop_test.go:86: [test-00] 6 TestLoopInfinite: loop_test.go:86: [test-00] 7 TestLoopInfinite: loop_test.go:86: [test-00] 8 TestLoopInfinite: loop_test.go:86: [test-00] 9 TestLoopInfinite: loop_test.go:86: [test-00] 10 --- PASS: TestLoopInfinite (1.11s) PASS ok github.com/devlights/gomy/chans 1.228s
参考
- 作者:Katherine Cox-Buday
- 発売日: 2018/10/26
- メディア: 単行本(ソフトカバー)
関連記事
過去の記事については、以下のページからご参照下さい。
- いろいろ備忘録日記まとめ
サンプルコードは、以下の場所で公開しています。
- いろいろ備忘録日記サンプルソース置き場