golang 3ways to iterate

goの3つのiterator
================

参考元
<https://blog.kowalczyk.info/article/1Bkr/3-ways-to-iterate-in-go.html>
github
<https://github.com/kjk/go-cookbook/tree/master/3-ways-to-iterate>

こちらのgolangのiteratorに関する記事が参考になったので、まとめました。

3つの common iteration patternがgoにはあるそうです。

- callbacks
- an iterator object with Next() method
- channels

callback
--------

```go
func iterateOddNums(max int, f func(n int) error) error {
 if max < 0 {
     return errors.New("max must be greater than 0")
 }
 for i := 1; i <= max; i += 2 {
     err := f(i)
     if err != nil {
         return err
     }
 }
 return nil
}

func printOddNumbers(max int) error {
 err := iterateOddNums(max, func(n int) error {
     fmt.Printf("%d\n", n)
     return nil
 })
 return err
}

func main() {
 if err := printOddNumbers(20); err != nil {
     log.Fatal(err)
 }
}
```

関数を引数でもらうpattern。
callback関数はiterateを中断するべきかどうかの情報を返す 
``filepath.Walk`` で使われているpatternとのこと

next
----

```go
type OddNumIterator struct {
 max     int
 current int
 err     error
}

func NewOddNumIterator(max int) *OddNumIterator {
 var err error
 if max < 0 {
     err = errors.New("max must be greater than 0")
 }
 return &OddNumIterator{
     max:     max,
     current: 1,
     err:     err,
 }
}

func (i *OddNumIterator) Next() bool {
 if i.err != nil {
     return false
 }
 i.current += 2
 return i.current <= i.max
}

func (i *OddNumIterator) Value() int {
 if i.err != nil || i.current > i.max {
     panic("something wrong")
 }
 return i.current
}

func (i *OddNumIterator) Err() error {
 return i.err
}

func printOddNums(max int) error {
 iter := NewOddNumIterator(max)
 for iter.Next() {
     fmt.Printf("%d\n", iter.Value())
 }
 return iter.Err()
}

func main() {
 if err := printOddNums(20); err != nil {
     log.Fatal(err)
 }
}
```

-   `database/sql` の `Rows.Next`
-   `bufio` の `Scanner.Scan`

等で利用されていると思います

goroutine safeにするには, `sync.Mutex` を埋め込むべきか。 
`Value()` がintのみを返すために、中でpanicを呼ぶのも直したい

channel
-------

```go
type IntWithErr struct {
 Int int
 Err error
}

func generateOddNums(ctx context.Context, max int) <-chan IntWithErr {
 ch := make(chan IntWithErr)
 go func() {
     defer close(ch)
     if max < 0 {
         ch <- IntWithErr{
             Err: errors.New("max must be greater than 0"),
         }
         return
     }

     for i := 1; i <= max; i += 2 {
         if ctx != nil {
             select {
             case <-ctx.Done():
                 return
             default:
             }
         }
         ch <- IntWithErr{
             Int: i,
         }
     }
 }()
 return ch
}

func printOddNums(max int, stopAt int) error {
 ctx, cancel := context.WithCancel(context.Background())
 defer cancel()
 ch := generateOddNums(ctx, 20)

 for val := range ch {
     if val.Err != nil {
         return val.Err
     }
     if val.Int > stopAt {
         cancel()
         break
     }
     fmt.Printf("%d\n", val.Int)
 }

 // drain
 for _ = range ch {
 }
 return nil
}

func main() {
 if err := printOddNums(100, 20); err != nil {
     log.Fatal(err)
 }
}
```

channelを利用するとpythonのgeneratorのように利用できるのだろうか。
`cancel()`を読んでも、呼んだ先が処理を停止する保証がないので、channelからdrainしないとgoroutine leak(?) するとのこと。

```go
go func() {
   for _ = range ch {
   }
}()
```
のようにdrain処理も別のgoroutineに切り出したほうが安全かなと思った。


どれがBestか
------------

> The one that best fits your scenario.

やっぱりそうですよね.