ジェネレーター関数は説明が難しいが、一言で言うと「値を小出しに返す関数(を作る関数)」。Pythonでは例えばこう使える。イタレータを作る関数と言っても良いかも。
def firstn(n):
num = 0
while num < n:
yield num
num += 1
gen = firstn(10)
print gen.next() # —> 0
print gen.next() # —> 1
print gen.next() # —> 2
…
print gen.next() # —> 11回目は StopIteration 例外が起きる
当然、forループやリスト内包表記でも使える。
for n in firstn(10):
print n,
# —> 0 1 2 3 4 5 6 7 8 9
print [n for n in firstn(10)]
# -> [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
で、このジェネレータ関数をJavaScriptでも使えるようになるらしい。正式にはES6 (ECMAScript version 6)で規格化される予定だが、幾つかの実装は既にこの機能を取り入れ始めている。
Node.jsも次の安定版v0.12で正式採用すべく、v0.11でジェネレータが使えるようになっている。で、それを使ってみた。
まず上の例をJavaScriptで書きなおし。
firstn = function* (n) {
var num = 0
while (num < n) {
yield num
num += 1
}
};
gen = firstn(10);
console.log(gen.next()); // —> { value: 0, done: false }
console.log(gen.next()); // —> { value: 1, done: false }
console.log(gen.next()); // —> { value: 2, done: false }
…
console.log(gen.next()); // —> 11回目は { value: undefined, done: true } が返る
Pythonと違うのは値が返るのではなく、valueとdoneという二つのattributeを持つobjectが返るということ。繰り返しが終わったときには例外を発生させるのではなく、doneがtrueになる。
なお実行時には node —harmony
とする。”Harmony”はES6のコードネームらしい。
そしてこれもforループで使える
for (n of firstn(10)) {
process.stdout.write(n + " ");
}
// —> 0 1 2 3 4 5 6 7 8 9
ES6ではリスト内包表記も使えるようになるらしいのだが、現在の最新版 (0.11.9)では未サポート。残念。