在Flutter中,“yield”关键字的作用是什么?

111
< p > 在Dart中,< code > yield < /code > 关键字实际上是什么作用?< /p >
4个回答

159

yield 将一个值添加到包围的 async* 函数的输出流中。它类似于 return,但不会终止函数。

请参阅 https://dart.dev/guides/language/language-tour#generators

Stream asynchronousNaturalsTo(n) async* {
  int k = 0;
  while (k < n) yield k++;
}

当yield语句执行时,它会将其表达式的计算结果添加到流中。它不一定会挂起(尽管在当前的实现中它会挂起)。


25
这就像return,但不会终止函数。 - anothercoder
1
完美,加一,简短的完整答案和比较。 - Kohls
重要的一点要提到:在async*函数中,yield暂停当前任务的执行,并将其切换到调用者(await for循环)。如果不注意这一点,可能会导致非常奇怪的执行停顿。以下是一些示例来突出潜在的问题:非停顿示例停顿示例 - undefined

130
被接受的答案链接已经失效了,这里是关于 async* sync* yield* yield 的官方链接。
如果您有其他语言的经验,您可能会卡在这些关键字上。以下是一些克服关键字的提示:
  1. async* sync* yield* yield 被称为生成器函数。您可能会在Bloc模式中大量使用这些函数。

  2. async* 也是一个 async,您可以像往常一样使用异步

  3. sync* 不能像 sync 一样使用,否则您将收到错误提示"The modifier sync must be followed by a star"

  4. yieldyield* 只能与生成器函数async* sync*)一起使用。

还有四种组合方式:
  1. async* yield 将返回一个 Stream<dynamic>
Stream<int> runToMax(int n) async* {
  int i = 0;
  while (i < n) {
    yield i;
    i++;
    await Future.delayed(Duration(seconds: 300));
  }
}
  1. async* yield* 会调用一个函数并返回 Stream<dynamic>
Stream<int> countDownFrom(int n) async* {
  if (n > 0) {
    yield n;
    yield* countDownFrom(n - 1);
  }
}
  1. sync* yield 将返回一个 Iterable<dynamic>
Iterable<int> genIterates(int max) sync* {
  var i = 0;
  while (i < max) {
    yield i;
    i++;
  }
}
  1. sync* yield* 会调用一个函数并返回 Iterable<dynamic>
Iterable<int> countDownFrom(int n) sync* {
  if (n > 0) {
    yield n;
    yield* countDownFrom(n - 1);
  }
}

如有任何错误,请留下评论以更正答案。


1
我修复了我的回答中的链接。 - Jacob Phillips
28
我认为yield的正确答案是将任务委托给另一个生成器而不是调用函数。yield简单地将任务委托给另一个生成器,这意味着当前的生成器停止工作,直到另一个生成器停止产生值。在那个生成器停止产生值之后,主生成器会继续产生自己的值。 - mirkancal
4
@mirkancal的解释非常清晰明了,应该写成答案而不仅仅是一条评论。 - András Szepesházi

17

我认为yield*的正确答案是将任务委派给另一个生成器而不是调用函数。yield*仅仅是将任务委派给另一个生成器,这意味着当前生成器停止执行,直到另一个生成器产生结果。在另一个生成器停止产生值之后,主生成器会恢复执行并继续产生自己的值。

感谢@András Szepesházi鼓励我将此评论作为答案发布,希望可以帮到您。


很好的答案。我正在寻找这个。 - Ben Butterworth
谢谢,正是我所需要的。除了你的回答,yield* 还有以下用途:A. 通过嵌套多个生成器来重构生成器代码 B. 递归生成器。 - om-ha
如果你的生成器是递归的,你可以通过使用yield*来提高其性能。 - om-ha

3
yield语句只能在生成器函数中使用。
生成器函数以自然的方式生成数据项(如计算、从外部接收、预定义值等)。
当下一个数据项准备好时,yield语句会将该项发送到数据序列中,这本质上是函数的生成结果。
数据序列可以是同步的或异步的。
在Dart语言中,同步的数据序列意味着Iterable实例。
异步的数据序列意味着Stream实例。
附注:
生成器函数可以无限生成数据项,直到函数返回为止。
但与普通函数不同的是,结果(即数据序列)将立即在函数调用后返回并可立即使用。
在这种情况下,数据序列的末尾只有在生成器函数被终止(成功或失败)时才能到达。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接