チャネルを使って、数列を生成することを考える。数列のような一連のデータの流れを、ストリームとよぶ。
まずは単純な例から。
package main import ( "fmt" ) type Stream chan int func makeInt(n, m int) Stream { s := make(Stream) go func() { for i := n; i <= m; i++ { s <- i } close(s) }() return s } func main() { s := makeInt(1, 20) for x := range s { fmt.Print(x, " ") } fmt.Println("") }
type
を使って、整数をやり取りするチャネルに Stream
という別名をつけている。makeInt
関数は、整数2つ(n
と m
)を引数にとって Stream
を返す。中では、Stream
を作っておき、ゴルーチンで匿名関数を実行する。このゴルーチンは for
ループの中で n
から m
までを Stream
に書き込み、最後に閉じる。
こうすることによって、数列が生成できるわけだ。
実行例:
^o^ > go run stream.go 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20
次に、Stream
を高階関数に渡してみよう。マッピングを行う streamMap
とフィルタリングを行う streamFilter
を作ってみる。どちらも関数と Stream
を受け取って、新しい Stream
を返す。
package main import ( "fmt" ) type Stream chan int func makeInt(n, m int) Stream { s := make(Stream) go func() { for i := n; i <= m; i++ { s <- i } close(s) }() return s } func streamMap(f func(int) int, in Stream) Stream { s := make(Stream) go func() { for { x, ok := <- in if !ok { break } s <- f(x) } close(s) }() return s } func streamFilter(f func(int) bool, in Stream) Stream { s := make(Stream) go func() { for { x, ok := <- in if !ok { break } if f(x) { s <- x } } close(s) }() return s } func main() { s0 := makeInt(1, 20) for x := range s0 { fmt.Print(x, " ") } fmt.Println("") square := func(x int) int { return x * x } s1 := streamMap(square, makeInt(1, 20)) for x := range s1 { fmt.Print(x, " ") } fmt.Println("") isOdd := func(x int) bool { return x % 2 != 0 } s2 := streamFilter(isOdd, makeInt(1, 20)) for x := range s2 { fmt.Print(x, " ") } fmt.Println("") }
実行例:
^o^ > go run stream2.go 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 1 4 9 16 25 36 49 64 81 100 121 144 169 196 225 256 289 324 361 400 1 3 5 7 9 11 13 15 17 19