Posted at

GeneratorとSequence

More than 3 years have passed since last update.


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)
}