Help us understand the problem. What is going on with this article?

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

More than 1 year has passed since last update.

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

概要

  • ジェネレーターの例にありがちなフィボナッチ数を作ってみる
  • クロージャを使う
  • UnfoldSequenceを使う
    • GeneratorTypeというprotocolがあるみたいですが、UnfoldSequence使った実装のほうが簡潔に感じました
  • deferで関数を抜ける際にステートを更新
    • Go言語にもあるリソースのクローズとかによく使われるやつ

実装

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上でのやりとり

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 さんありがとうございました。

参考

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

shisama
Node.js Core Collaborator. 関西Node学園Organizer.
https://shisama.dev
Why not register and get more from Qiita?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
Comments
No comments
Sign up for free and join this conversation.
If you already have a Qiita account
Why do not you register as a user and use Qiita more conveniently?
You need to log in to use this function. Qiita can be used more conveniently after logging in.
You seem to be reading articles frequently this month. Qiita can be used more conveniently after logging in.
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
ユーザーは見つかりませんでした