Swiftでフィボナッチ数列ジェネレーターをサクッと作る

Swift初心者レベルですが、勉強会でイテレーターについて色々と学んだので「ジェネレーターもサクッと作れそうだな」と思い作ってみました。
メモ程度ですが、参考になれば幸いです。
その勉強会→[みんなで Swift 復習会 GO! in 京都 – 6th′](https://cswift.connpass.com/event/70814/)

# 概要
- ジェネレーターの例にありがちな[フィボナッチ数](https://ja.wikipedia.org/wiki/フィボナッチ数)を作ってみる
- クロージャを使う
- [UnfoldSequence](https://developer.apple.com/documentation/swift/unfoldsequence)を使う
  - GeneratorTypeというprotocolがあるみたいですが、[UnfoldSequence](https://developer.apple.com/documentation/swift/unfoldsequence)使った実装のほうが簡潔に感じました
- deferで関数を抜ける際にステートを更新
  - Go言語にもあるリソースのクローズとかによく使われるやつ


# 実装

```swift
func generateFibonacci() -> UnfoldSequence<Int, (current: Int, next: Int)> {
    // クロージャ関数を返す
    return sequence(state: (0, 1)) { state -> Int in
        // 関数を抜けるときにステートを更新
        defer {
            state = (
                current: state.next,
                next: state.current + state.next
            )
        }
        return state.current
    }
}

// fibonacci変数にはUnfoldSequnceのインスタンスが格納される
var fibonacci = generateFibonacci()

// UnfoldSequenceのnext()関数を実行すると現在の値を取得し、
// フィボナッチ数を更新
print(fibonacci.next()) // Optional(0)
print(fibonacci.next()) // Optional(1)
print(fibonacci.next()) // Optional(1)
print(fibonacci.next()) // Optional(2)
print(fibonacci.next()) // Optional(3)
print(fibonacci.next()) // Optional(5)
print(fibonacci.next()) // Optional(8)
print(fibonacci.next()) // Optional(13)
print(fibonacci.next()) // Optional(21)
print(fibonacci.next()) // Optional(34)
print(fibonacci.next()) // Optional(55)
print(fibonacci.next()) // Optional(89)
print(fibonacci.next()) // Optional(144)
```

UnfoldSequenceはSequenceプロトコルだけでなくIteratorProtocolにも準拠しているため`next()`が使えるようになっています。Sequenceだけだと`next()`は使えませんが、`makeIterator()`でイテレーターインスタンスを取得することで`next()`を使うことができます。このことは以下に追記しているので併せて拝見していただけると幸いです。

個人的にはswiftにもyieldがあれば、ぱっと見たときにジェネレーター関数ってわかりやすいかもなと感じました。

あと、JavaScriptのジェネレーターみたいにnext().valueとしなくていいのは良いなと感じました。

# 追記(2018/01/16)
以下のような方法でも同じようなことができます。@es_kumagai さんにTwitter上で教えていただいたことを基にしています。ありがとうございます！
`next()`は使えませんが、そのかわりに`sequence`の実装がスッキリ書けました。
~~配列の添字用に`index()`関数を作りましたが、これはSwiftに`++`のインクリメントが無いため`count++`の代用です。~~
`makeIterator()`を使えば配列の添字を意識する必要はないことも教えていただきました。`makeIterator()`でIteratorProtocolに準拠したオブジェクトを生成します。そのため、`next()`関数を使用することができます。
ちなみにXcode9のplaygroundでは動きましたが、Xcode8では動きませんのでご注意ください。
[@es_kumagaiさんとのTwitter上でのやりとり](https://twitter.com/es_kumagai/status/952414083336175623)

```swift
let fibonacci = sequence(state: (current: 0, next: 1)) { state -> Int in
    defer {
        state = (current: state.next, next: state.current + state.next)
    }
    return state.current
}

var iterator = fibonacci.makeIterator()

print(iterator.next()) // Optional(0)
print(iterator.next()) // Optional(1)
print(iterator.next()) // Optional(1)
print(iterator.next()) // Optional(2)
print(iterator.next()) // Optional(3)
print(iterator.next()) // Optional(5)
print(iterator.next()) // Optional(8)
print(iterator.next()) // Optional(13)
print(iterator.next()) // Optional(21)
print(iterator.next()) // Optional(34)
print(iterator.next()) // Optional(55)
print(iterator.next()) // Optional(89)
print(iterator.next()) // Optional(144)
```

最終的にかなり簡潔になりました。
かなりサクッとフィボナッチ数を返すイテレーターオブジェクトができました。
@es_kumagai さんやコメントくださった @lovee さん、 @t-ae さんありがとうございました。

# 参考
- [UnfoldSequence](https://developer.apple.com/documentation/swift/unfoldsequence)
- [Swift 2のdefer文](https://qiita.com/takebayashi/items/541db03c7449ee41fd36)
- [Swift 3 でジェネレータを作ったり、遅延評価してみる](http://ryota-ka.hatenablog.com/entry/2017/07/16/045327)
- [GeneratorとSequence](https://qiita.com/naoty_k/items/970796fe56b4ab083278)
- [[Swift] シンプルなカウントアップでSequenceに強くなる](https://qiita.com/a-beco/items/2c0432217bbf41ee54e3)
- [Go言語のdeferでファイルリソースをクローズする](http://y0m0r.hateblo.jp/entry/20130925/1380117667)

以上になります。
お読み頂きありがとうございました。