LoginSignup
63
63

More than 5 years have passed since last update.

GeneratorとSequence

Posted at

GeneratorType

generatorとは新しい要素を返す処理のことで、以下のGeneratorTypeプロトコルに従う。

protocol GeneratorType {
    typealias Element
    func next() -> Element?
}

例えば、文字列を各行を返すgeneratorはこんな感じで実装する。

class LineGenerator: GeneratorType {
    typealias Element = String

    var lines: [String]

    init(text: String) {
        self.lines = text.componentsSeparatedByString("\n")
    }

    func next() -> Element? {
        return lines.isEmpty ? nil : lines.removeAtIndex(0)
    }
}

let text = "いろはにほへと ちりぬるを\nわかよたれそ つねならむ\nういのおくやま けふこえて\nあさきゆめみし よひもせず"
let generator1 = LineGenerator(text: text)
generator1.next() //=> いろはにほへと ちりぬるを
generator1.next() //=> わかよたれそ つねならむ
generator1.next() //=> ういのおくやま けふこえて
generator1.next() //=> あさきゆめみし よひもせず
generator1.next() //=> nil

GeneratorOf

generatorを書くとき上のようにクラスを定義するのが面倒なら、GeneratorOf<T>構造体が便利。以下のような感じで定義されている。

struct GeneratorOf<T>: GeneratorType, SequenceType {
    init(_ nextElement: () -> T?)

    mutating func next() -> T?
}

GeneratorOf構造体はGeneratorTypeプロトコルに従っており、初期化時に渡されたクロージャをnext()で実行するようになっている。なので、上のコードは以下のように書き直せる。

func lineGenerator(#text: String) -> GeneratorOf<String> {
    var lines = text.componentsSeparatedByString("\n")
    return GeneratorOf { return lines.isEmpty ? nil : lines.removeAtIndex(0) }
}

var generator2 = lineGenerator(text: text)
generator2.next() //=> いろはにほへと ちりぬるを
generator2.next() //=> わかよたれそ つねならむ
generator2.next() //=> ういのおくやま けふこえて
generator2.next() //=> あさきゆめみし よひもせず
generator2.next() //=> nil

SequenceType

sequenceはループによって中身の要素を走査できる構造のことで、以下のSequenceTypeプロトコルに従う。

protocol SequenceType {
    typealias Generator: GeneratorType
    func generate() -> Generator
}

sequenceはgeneratorをgenerate()で生成して、それを使って中身の要素に順にアクセスする。SequenceTypeプロトコルに従うオブジェクトはfor-inループに渡すことができる。

class LineSequence: SequenceType {
    typealias Generator = LineGenerator

    var text: String

    init(text: String) {
        self.text = text
    }

    func generate() -> Generator {
        return LineGenerator(text: text)
    }
}

for line in LineSequence(text: text) {
    print(line)
}

SequenceOf

GeneratorOfと同様にSequenceOfも存在する。

struct SequenceOf<T>: SequenceType {
    init<G: GeneratorType where T == T>(_ makeUnderlyingGenerator: () -> G)
    func generate() -> GeneratorOf<T>
}
func lineSequence(#text: String) -> SequenceOf<String> {
    return SequenceOf { return lineGenerator(text: text) }
}

for line in lineSequence(text: text) {
    print(line)
}
63
63
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
63
63