golangでのイテレーターの実装方法を
ググって見つけたのがこちらの記事
http://ewencp.org/blog/golang-iterators/
こちらにある4種類の方法が主な方法かと思いますが、
気に入ったのは、
チャンネルを使ったパターンとコールバックを使ったパターンの2つ。
チャンネルパターン
コードの書き方としては、
このパターンが一番しっくりくるのですが、、
チャンネルパターン
func IntChannelIterator() <-chan int {
ch := make(chan int)
go func() {
for _, val := range int_data {
ch <- val
}
close(ch) // Remember to close or the loop never ends!
}()
return ch
}
チャンネルパターン使用例
var sum int = 0
for val := range IntChannelIterator() {
sum += val
}
他のパターンと比べると致命的に遅いのが欠点です。
以下は、上記ページにあったコードをgo ver1.4.1を使って
MacBook Pro (Retina, Mid 2012) で実測結果です。
$ go version
go version go1.4.1 darwin/amd64
$ go test -bench .
testing: warning: no tests to run
PASS
BenchmarkIntsCallbackIterator 500 2733180 ns/op
BenchmarkDataCallbackIterator 500 3142514 ns/op
BenchmarkIntsChannelIterator 5 269527633 ns/op
BenchmarkDataChannelIterator 5 266374326 ns/op
BenchmarkIntsBufferedChannelIterator 20 94554939 ns/op
BenchmarkDataBufferedChannelIterator 20 93447309 ns/op
BenchmarkIntsClosureIterator 300 5030297 ns/op
BenchmarkDataClosureIterator 300 4855251 ns/op
BenchmarkIntStatefulIterator 1000 2333693 ns/op
BenchmarkDataStatefulIterator 500 2490458 ns/op
BenchmarkIntStatefulIteratorInterface 200 6054515 ns/op
BenchmarkDataStatefulIteratorInterface 200 6797890 ns/op
ok github.com/masahide/golang-iterators-benchmark 26.820s
ここまで速度差が出てしまうと、繰り返し処理としては致命的かもしれません。。
チャンネルバッファを使ってもまだまだ・・・。
コールバックパターン
そこで、速さと、コードの書きやすさを両立したコールバックパターンです。
コールバックパターン
func IntCallbackIterator(cb func(int)) {
for _, val := range int_data {
cb(val)
}
}
コールバックパターンの使用例
var sum int = 0
IntCallbackIterator(func(val int) {
sum += val
})
その他のパターン
なんというか中途半端感があって興味が出ません。。
スピードにこだわるならStatefulパターンですね。でもコールバックとそれほど違わないので、うーん。