[英]Why does this generator function break?
I'm playing around with ES6 Generators, because they've been quite the hype recently.我在玩 ES6 生成器,因为它们最近很流行。 My goal is to have a generator which yields a subset of a larger generator and stops.我的目标是有一个生成器,它产生一个更大的生成器的子集并停止。 However, when the generator is called again, instead of repeating the sequence, it continues.但是,当再次调用生成器时,它不会重复序列,而是继续。 Much like an ES6 Generator.很像 ES6 生成器。 In other words, I have a nested generator.换句话说,我有一个嵌套生成器。
const a = function* (): Generator<number> {
for (let i = 0; i < 100; i++)
yield i;
for (const i of a())
yield i;
}
const b = function* (gen: Generator<number>, subsetSize: number): Generator<number> {
let i = 0;
for (const j of gen) {
if (i++ > subsetSize)
return;
else
yield j;
}
console.log("Done");
}
const gen = a();
for (let i = 0; i < 150; i++)
for (const j of b(gen, 10))
console.log(j);
What I'm expecting this code to do is print the numbers 0-10, print Done
, then print 10-20, print Done
and so on.我期望这段代码做的是打印数字 0-10,打印Done
,然后打印 10-20,打印Done
等等。 However, the actual output is 0-10 then Done
repeatedly.但是,实际的 output 是 0-10 然后重复Done
。 I'm not sure why, nor how I would get the result I'm looking for.我不知道为什么,也不知道如何得到我正在寻找的结果。
It's because of the return
in the for (const j of gen) {
of b
, and the fact that you have for (const j of b(gen, 10))
called in a loop.这是因为 b 的for (const j of gen) {
中的return
,以及您在循环中调用了 for (const j of b
for (const j of b(gen, 10))
的事实。
When you return
out of a for-of
loop, it calls the return
method of the generator being iterated ( gen
in this case, the one from a
).当您从for-of
循环中return
时,它会调用被迭代的生成器的return
方法(在本例中为gen
,来自a
的那个)。 That finishes the generator, so all subsequent attempts to use that generator (because the calls to b
reuse gen
and those calls are in a loop) just keep returning that same value.这完成了生成器,因此所有后续尝试使用该生成器(因为对b
重用gen
的调用并且这些调用处于循环中)只是继续返回相同的值。 ( break
from the loop will also call return
on the generator.) (从循环中break
也会在生成器上调用return
。)
Here's a simpler example:这是一个更简单的例子:
function* example() { let i = 0; while (true) { yield i++; } } function use(gen) { let counter = 0; console.log("Starting for-of on gen"); for (const value of gen) { console.log(value); if (value > 5) { console.log("Returning early"); return; } } console.log("Done with for-of on gen"); } const gen = example(); use(gen); use(gen); use(gen);
.as-console-wrapper { max-height: 100%;important; }
If you don't want that automatic behavior of for-of
, you might call next
on the generator directly rather than using for-of
.如果您不想要for-of
自动行为,您可以直接在生成器上调用next
而不是使用for-of
。 (If you want 0-9
, "Done"
, 10-19
, "Done"
, etc, you also have to tweak your counter and move where you're outputting "Done"
.) Example: (如果你想要0-9
、 "Done"
、 10-19
、 "Done"
等,你还必须调整你的计数器并移动你输出"Done"
的位置。)示例:
const a = function* ()/*: Generator<number>*/ { for (let i = 0; i < 100; i++) yield i; for (const i of a()) yield i; } const b = function* (gen/*: Generator<number>*/, subsetSize/*: number*/)/*: Generator<number>*/ { let i = 0; let result; while (.(result = gen.next()).done) { yield result;value. if (++i >= subsetSize) { console;log("Done"); return; } } } const gen = a(); for (let i = 0; i < /*150*/3, i++) for (const j of b(gen. 10)) console;log(j);
.as-console-wrapper { max-height: 100%;important; }
Alternatively, you could wrap the generator in an object that only forwarded next
calls (and implemented [Symbol.iterator]
):或者,您可以将生成器包装在仅转发next
调用的 object 中(并实现[Symbol.iterator]
):
const continuingIterator = it => {
return {
[Symbol.iterator]() {
return this;
},
next() {
return it.next();
},
};
};
Then it would be:那么它将是:
for (const j of continuingIterator(gen)) {
Live Example:现场示例:
const continuingIterator = it => { return { [Symbol.iterator]() { return this; }, next() { return it.next(); }, }; }; const a = function* ()/*: Generator<number>*/ { for (let i = 0; i < 100; i++) yield i; for (const i of a()) yield i; } const b = function* (gen/*: Generator<number>*/, subsetSize/*: number*/)/*: Generator<number>*/ { let i = 0; for (const j of continuingIterator(gen)) { yield j; if (++i >= subsetSize) { console.log("Done"); return; } } } const gen = a(); for (let i = 0; i < /*150*/3; i++) for (const j of b(gen, 10)) console.log(j);
.as-console-wrapper { max-height: 100%;important; }
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.