概要
引き続き、小ネタチャネル関数の続き。( #関連記事 参照)
python には、mapというビルドイン関数があります。
こんな感じ。
$ python3 Python 3.7.7 (default, Mar 25 2020, 10:55:55) [GCC 8.3.0] on linux Type "help", "copyright", "credits" or "license" for more information. >>> def fn(x:int) -> int: ... return x**2 ... >>> l = [1,2,3] >>> print(*map(fn, l)) 1 4 9
チャネルからの要素に対しても同じようにしたいときがあります。
なので、ちょっとサンプル作ってみました。
サンプル
package chans type ( // MapFunc -- chans.Map にて利用されるチャネルの各要素に適用する関数です。 MapFunc func(interface{}) interface{} // MapValue -- chans.Map にて利用されるデータ型です。 MapValue struct { Before interface{} // 元の値 After interface{} // 適用後の値 } ) func newMapValue(before, after interface{}) *MapValue { return &MapValue{ Before: before, After: after, } } // Map -- 関数 fn を入力チャネル in の各要素に適用した結果を返すチャネルを生成します。 // // 戻り値のチャネルから取得できるデータ型は、*chans.MapValue となっています。 // // for m := range chans.Map(done, inCh, fn) { // if v, ok := m.(*chans.MapValue); ok { // // v.Before で元の値、 v.After で適用後の値が取得できる // } // } // func Map(done <-chan struct{}, in <-chan interface{}, fn MapFunc) <-chan interface{} { out := make(chan interface{}) go func() { defer close(out) ChLoop: for { select { case <-done: break ChLoop case v, ok := <-in: if !ok { break ChLoop } before := v after := fn(v) select { case out <- newMapValue(before, after): case <-done: } } } }() return out }
gomy/map.go at master · devlights/gomy · GitHub
以下テストコードです。
package chans import ( "reflect" "strings" "testing" ) func TestMap(t *testing.T) { type ( testin struct { input []interface{} fn MapFunc } testout struct { result []interface{} } testcase struct { in testin out testout } ) cases := []testcase{ { in: testin{ input: []interface{}{"hello", "world"}, fn: func(v interface{}) interface{} { return strings.ToUpper(v.(string)) }, }, out: testout{result: []interface{}{"HELLO", "WORLD"}}, }, } for caseIndex, c := range cases { func() { done := make(chan struct{}) defer close(done) results := make([]interface{}, 0, 0) for m := range Map(done, ForEach(done, c.in.input...), c.in.fn) { if v, ok := m.(*MapValue); ok { t.Logf("[test-%02d] [%v] ==> [%v]", caseIndex, v.Before, v.After) results = append(results, v.After) } } if !reflect.DeepEqual(c.out.result, results) { t.Errorf("want: %v\tgot: %v", c.out.result, results) } }() } }
実行すると以下のようになります。
$ go test -v github.com/devlights/gomy/chans -run ^TestMap.*$ === RUN TestMap TestMap: map_test.go:45: [test-00] [hello] ==> [HELLO] TestMap: map_test.go:45: [test-00] [world] ==> [WORLD] --- PASS: TestMap (0.00s) PASS ok github.com/devlights/gomy/chans 0.004s
参考
- 作者:Katherine Cox-Buday
- 発売日: 2018/10/26
- メディア: 単行本(ソフトカバー)
関連記事
過去の記事については、以下のページからご参照下さい。
- いろいろ備忘録日記まとめ
サンプルコードは、以下の場所で公開しています。
- いろいろ備忘録日記サンプルソース置き場