什么是生成器函数
Dart生成器函数 (generator) 可以渐进的返回一个值的序列。
Dart内置了两种生成器函数的支持:
同步生成器(sync*):返回一个Iterable对象。 异步生成器(async*):返回一个Stream对象。
同步生成器
使用同步生成器修饰的函数返回的是迭代器Iterable
Iterable主要使用iterator的两个方法moveNext(),current,current代表了当前元素,moveNext()将迭代器推进到迭代的下一个元素。
用一段代码展示如何使用同步生成器:
Iterable<int> naturalsTo(int n) sync* {
int k = 0;
while (k < n) yield k++;
}
测试代码:
void main() {
Iterable<int> sequence = naturalsTo(5);
print("Starting...");
for (int value in sequence) {
print(value);
}
print("DONE");
}
输出如下:
Starting... 0 1 2 3 4 DONE
代码解读:
上面示例中的naturalsTo函数就是使用同步生成器修饰的函数,首先在函数方法体花括号前加入sync*关键字,然后使用yield关键字进行值的返回。
上面的代码示例yield关键字向迭代器序列依次添加了五个值。
看到这里你可能有点疑问,函数返回值不是return吗?yield是干嘛的?
yield和yield*
yield的作用:
yield向周围sync*函数的迭代器中添加一个值。就像return,但不会终止函数。
上面的代码示例yield关键字向迭代器序列依次添加了五个值。
与yield功能类似的还有一个关键字yield*,yield*只是一种简化写法。如果生成器是递归的,可以使用 yield* 来提高其性能。
用两段代码示例来展示yield*是如何简化代码的:
这是一段没有使用yield*的代码:
void main() {
for (int i in numbersDownFrom(3)) {
print('$i');
}
}
Iterable<int> numbersDownFrom(int n) sync* {
if (n != 0) {
yield n;
for (var val in numbersDownFrom(n - 1)) {
yield val;
}
}
}
输出如下:
3 2 1
for (var val in numbersDownFrom(n - 1)) {
yield val;
}
这段代码是函数的递归调用,代码流程完全是同步的,你可能要花上一点时间阅读一下代码,你就能理解这段代码做了什么事情。
接下来我们用yield*来简化这段代码:
void main() {
for (int i in numbersDownFrom(3)) {
print('$i');
}
}
Iterable<int> numbersDownFrom(int n) sync* {
if (n != 0) {
yield n;
yield* numbersDownFrom(n - 1);
}
}
输出如下:
3 2 1
两段代码的作用完全一样,你应该已经理解yield*的作用了,就是对For循环+yield的一种简化。
异步生成器
异步生成器async*在原理上和同步生成器完全一样,都是渐进的返回一个值的序列,唯一区别就是同步生成器返回的是迭代器。异步声明器返回的是Stream。
关于Stream的详细介绍参考作者之前的文章。
用一段与上面sync*使用方式一样的代码来为你展示如何使用异步生成器async*
Stream<int> naturalsTo(int n) async* {
int k = 0;
while (k < n) yield k++;
}
测试代码:
void main() async{
Stream<int> sequence = naturalsTo(5);
print("Starting...");
await for (int value in sequence) {
print(value);
}
print("DONE");
}
输出如下:
Starting... 0 1 2 3 4 DONE
async*与sync*工作原理完全一致,如果你对async和await for有疑问,参考作者之前的文章。
sync,sync*,async,async*
文章看到这里对异步的全部介绍已经结束了,用一张图片来帮助你记忆sync,sync*,async,async*的区别。