[英]Difference between yield and yield* in Dart
我想知道这两者有什么区别。 我在 javascript, Delegated yield (yield star, yield *) in generator functions上找到了这篇 SO post
据我了解, yield*
委托给另一个生成器,在另一个生成器停止生成值后,它会继续生成自己的值。
飞镖方面的解释和示例会有所帮助。
yield
它用于从异步或同步生成器发出值。
例子:
Stream<int> str(int n) async* {
for (var i = 1; i <= n; i++) {
await Future.delayed(Duration(seconds: 1));
yield i;
}
}
void main() {
str(3).forEach(print);
}
输出:
1
2
3
yield*
它将调用委托给另一个生成器,在该生成器停止生成值后,它会继续生成自己的值。
例子:
Stream<int> str(int n) async* {
if (n > 0) {
await Future.delayed(Duration(seconds: 1));
yield n;
yield* str(n - 1);
}
}
void main() {
str(3).forEach(print);
}
输出:
3
2
1
yield
从 Iterable 或 Stream 返回值。yield*
用于递归调用其 Iterable 或 Stream 函数。让我们看一下Generator Functions - Flutter in Focus视频中的一些示例。 我们将只看 Iterable 示例,但它与 Streams 类似。
这是一个从start
到finish
计数的 Iterable 。
Iterable<int> getRange(int start, int finish) sync* {
for (int i = start; i <= finish; i++) {
yield i;
}
}
yield
关键字在每次迭代时返回下一个值。
现在让我们将该函数重构为递归。 在外面,它仍然像以前一样做同样的事情:
Iterable<int> getRange(int start, int finish) sync* {
if (start <= finish) {
yield start;
for (final val in getRange(start + 1, finish)) {
yield val;
}
}
}
这有效,但由于循环而难以阅读且效率不高。
现在让我们使用yield*
(发音为“yield star”)再次重构它:
Iterable<int> getRange(int start, int finish) sync* {
if (start <= finish) {
yield start;
yield* getRange(start + 1, finish);
}
}
它仍然是递归的,但现在更容易阅读并且更高效。
我创建了一个飞镖板链接来帮助人们进行实验:
Yield* 用于在不使用循环的情况下一次产生一个完整的可迭代值。
这两个函数做完全一样的事情,根据开始和结束值生成一个可迭代对象。
Iterable<int> getRangeIteration(int start, int finish) sync* {
for(int i = start; i<= finish; i++){
yield i;
}
}
Iterable<int> getRangeRecursive(int start, int finish) sync* {
if (start <= finish) {
yield start;
yield* getRangeRecursive(start + 1, finish);
}
}
在第一个实现中(yield i)将暗示与函数的返回类型匹配的 Iterable 类型。
现在如果在第二个实现中而不是
yield* getRangeRecursive(start + 1, finish);
如果我们做了
yield getRangeRecursive(start + 1, finish);
我们会得到一个编译器错误:
The type 'Iterable<Iterable<int>>' implied by the 'yield' expression must be assignable to 'Iterable<int>'.
如您所见,yield 用另一个 Iterable<> 包装了 Iterable,这使得类型为 Iterable<Iterable>。
如果我们必须在不使用 yield* 的情况下进行递归,我们将不得不这样做:
Iterable<int> getRangeRecursiveWithOutYieldStar(int start, int finish) sync* {
if (start <= finish) {
yield start;
for (final val in getRangeRecursiveWithOutYieldStar(start + 1, finish)){
yield val;
}
}
}
这是混乱和低效的。
所以我觉得在我看来 yield* 扁平化了另一个生成器函数。
一些不错的资源:生成器函数 - Flutter in Focus 视频
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.