简体   繁体   English

Dart中yield和yield*之间的差异

[英]Difference between yield and yield* in Dart

I wanted to know what's the difference between this two.我想知道这两者有什么区别。 I find this SO post on javascript, Delegated yield (yield star, yield *) in generator functions我在 javascript, Delegated yield (yield star, yield *) in generator functions上找到了这篇 SO post

From what I understand, yield* delegates to the another generator and after the another generator stop producing values, then it resumes generating its own values.据我了解, yield*委托给另一个生成器,在另一个生成器停止生成值后,它会继续生成自己的值。

Explanation and examples on the dart side would be helpful.飞镖方面的解释和示例会有所帮助。

yield

It is used to emit values from a generator either async or sync.它用于从异步或同步生成器发出值。

Example:例子:

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

Output:输出:

1
2
3

yield*

It delegates the call to another generator and after that generator stops producing the values, it resumes generating its own values.它将调用委托给另一个生成器,在该生成器停止生成值后,它会继续生成自己的值。

Example:例子:

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

Output:输出:

3
2 
1 

Short answer简答

  • yield returns values from an Iterable or a Stream. yield从 Iterable 或 Stream 返回值。
  • yield* is used to recursively call its Iterable or Stream function. yield*用于递归调用其 Iterable 或 Stream 函数。

Examples例子

Let's look an some examples from the Generator Functions - Flutter in Focus video.让我们看一下Generator Functions - Flutter in Focus视频中的一些示例。 We'll just look at the Iterable example, but it's similar for Streams.我们将只看 Iterable 示例,但它与 Streams 类似。

Form 1表格 1

Here is an Iterable that counts from start to finish .这是一个从startfinish计数的 Iterable 。

Iterable<int> getRange(int start, int finish) sync* {
  for (int i = start; i <= finish; i++) {
    yield i;
  }
}

The yield keyword returns the next value on each iteration. yield关键字在每次迭代时返回下一个值。

Form 2表格 2

Now let's refactor that function to be recursive.现在让我们将该函数重构为递归。 On the outside it still does the same thing as before:在外面,它仍然像以前一样做同样的事情:

Iterable<int> getRange(int start, int finish) sync* {
  if (start <= finish) {
    yield start;
    for (final val in getRange(start + 1, finish)) {
      yield val;
    }
  }
}

This works but it's hard to read and not very efficient because of the loop.这有效,但由于循环而难以阅读且效率不高。

Form 3表格 3

Now let's refactor it again using yield* (pronounced "yield star"):现在让我们使用yield* (发音为“yield star”)再次重构它:

Iterable<int> getRange(int start, int finish) sync* {
  if (start <= finish) {
    yield start;
    yield* getRange(start + 1, finish);
  }
}

It's still recursive, but now it's easier to read and is more efficient.它仍然是递归的,但现在更容易阅读并且更高效。

I have created a dart pad link to help people experiment:我创建了一个飞镖板链接来帮助人们进行实验:

Yield* is used to yield a whole iterable one value at a time with out using a loop. Yield* 用于在不使用循环的情况下一次产生一个完整的可迭代值。

These 2 functions do exactly the same thing, generates an iterable based on the start and finish values.这两个函数做完全一样的事情,根据开始和结束值生成一个可迭代对象。

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

In the first implementation (yield i) would imply type Iterable which matches the function's return type.在第一个实现中(yield i)将暗示与函数的返回类型匹配的 Iterable 类型。

now if in the second implementation instead of现在如果在第二个实现中而不是

 yield* getRangeRecursive(start + 1, finish);

if we did如果我们做了

yield getRangeRecursive(start + 1, finish);

we will get a compiler error:我们会得到一个编译器错误:

The type 'Iterable<Iterable<int>>' implied by the 'yield' expression must be assignable to 'Iterable<int>'.

as you can see the yield wraps the Iterable with another Iterable<>, which makes the type Iterable<Iterable>.如您所见,yield 用另一个 Iterable<> 包装了 Iterable,这使得类型为 Iterable<Iterable>。

If we have to do recursion without using yield* we will have to do this:如果我们必须在不使用 yield* 的情况下进行递归,我们将不得不这样做:

Iterable<int> getRangeRecursiveWithOutYieldStar(int start, int finish) sync* {
  if (start <= finish) {
    yield start;
    for (final val in getRangeRecursiveWithOutYieldStar(start + 1, finish)){
    yield val;
    }
  }
}

Which is messy and inefficient.这是混乱和低效的。

So I feel like in my opinion yield* flattens another generator function.所以我觉得在我看来 yield* 扁平化了另一个生成器函数。

A few good resources: Generator Functions - Flutter in Focus video一些不错的资源:生成器函数 - Flutter in Focus 视频

Medium article: What are sync*, async*, yield and yield* in Dart?中篇文章: Dart 中的sync*、async*、yield 和yield* 是什么?

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM