MDNのジェネレーターに関するドキュメント を読んだ後、この簡単な実験を思いつきました。
_var nodes = {
type: 'root',
value: [
{ type: 'char', value: 'a' },
{ type: 'char', value: 'b' },
{ type: 'char', value: 'c' },
],
};
function* recursiveGenerator(node) {
if (node.type === 'root') {
node.value.forEach(function (subnode) {
for (var suffix of recursiveGenerator(subnode)) {
yield suffix;
}
});
}
else {
yield node.value;
}
}
for (generated of recursiveGenerator(nodes)) {
console.log(generated);
}
_
_--harmony
_フラグを設定してnode.js v0.11.9で実行すると、次のエラーが発生します。
_alix@900X4C:~$ node --version
v0.11.9
alix@900X4C:~$ node --harmony test.js
/home/alix/test.js:14
yield suffix;
^^^^^^
SyntaxError: Unexpected identifier
_
また、let
の代わりに_for ... in ...
_とvar
キーワードを使用してみましたが、成功しませんでした。
わかりません _yield*
_が正確に何をするか ですが、for
ループ内で使用すると、代わりに次のようになります。
_alix@900X4C:~$ node --harmony test.js
/home/alix/test.js:14
yield* suffix;
^
ReferenceError: yield is not defined
_
Forのyieldをconsole.log()
に置き換えると、a
、b
、およびc
が出力されます。私は何が間違っているのですか?
これは最小限のジェネレーターで、node.jsがジェネレーターの処理方法を知っていることを示しています。
_function* alpha() {
yield 'a';
yield 'b';
yield 'c';
}
for (var suffix of alpha()) {
console.log(suffix);
}
_
出力:
_alix@900X4C:~$ node --harmony y.js
a
b
c
_
_function* recursiveGenerator(node) {
if (node.type === 'root') {
for (var i = 0; i < node.value.length; ++i) {
var subnode = node.value[i];
for (var suffix of recursiveGenerator(subnode)) {
yield suffix;
}
}
}
else {
yield node.value;
}
}
for (generated of recursiveGenerator(nodes)) {
console.log(generated);
}
_
コメントの要約:regular関数内でyield
を使用できないため、yield
を使用できませんforEach
を使用します。 「生成された」foreachの例を次に示します。
function * foreach (arr, fn) {
var i
for (i = 0; i < arr.length; i++) {
yield * fn(arr[i])
}
}
function * gen (number) {
yield number + 1
yield number + 2
yield number + 3
}
function * other () {
yield * foreach([1, 2, 3], gen)
}
for (var i of other()) {
console.log(i)
}
[〜#〜] update [〜#〜]また、元の問題は、このようなヘルパーを使用して非常にエレガントに解決できます。
var nodes = {
type: 'root',
value: [
{ type: 'char', value: 'a' },
{ type: 'char', value: 'b' },
{ type: 'root', value: [
{ type: 'char', value: 'c' },
{ type: 'char', value: 'd' },
{ type: 'char', value: 'e' },
]
},
],
}
function * foreach (arr, fn) {
var i
for (i = 0; i < arr.length; i++) {
yield * fn(arr[i])
}
}
function * value (val) {
yield val
}
function * recursiveGenerator(node) {
yield * node.type === 'root' ? foreach(node.value, recursiveGenerator) : value(node.value)
}
for (var generated of recursiveGenerator(nodes)) {
console.log(generated);
}
したがって、ジェネレーター自体がワンライナーになります!
あなたはあなたの解決策を見つけましたが、ここでの記録のために、ツリー内のすべてのノードのタイプを出力する少し異なる別の例があります(私はいくつかの深さと変数を追加しました)
var nodes = {
type: 'root',
value: [
{ type: 'char', value: 'a' },
{ type: 'char', value: 'b' },
{ type: 'char', value: [{type: 'int', value: 'c'}] },
],
};
var flattenTree = function* (root) {
yield root.type;
var subvalues = root.value;
for(var i in subvalues) {
var gen = flattenTree(subvalues[i]);
val = gen.next();
while(!val.done) {
if(val.value != undefined)
yield val.value;
val = gen.next();
}
}
}
var printTree = function() {
console.log("begin tree");
var generator = flattenTree(nodes);
var next = generator.next();
while(!next.done) {
console.log(next);
next = generator.next();
}
console.log("finish tree");
}
printTree();
出力:
~/workspace/tmp$ ../node/node --harmony test-gen.js
begin tree
{ value: 'root', done: false }
{ value: 'char', done: false }
{ value: 'char', done: false }
{ value: 'char', done: false }
{ value: 'int', done: false }
finish tree