dart中的生成器函数
文章目录
2019 年春节前最后一更了
在 dart 中有生成器函数的语法,在很多其他的语言中也有,比如 js c#
这个语法看上去和 async
await
语法很像
使用的关键字是 async*
sync*
yield
yield*
官方对于这个语法的说明可以参考这个连接
其实async
await
也是一种生成器语法
生成器语法就是你返回的类型通常情况下和 return 的类型可能不一致
比如你return 1
,但是返回值上却需要写Future<int>
sync*
在 dart 中可以使用这个便利的生成一个迭代器
如下所示
这两种写法是一样的,但是第一个写法会简洁很多
1main(List<String> arguments) {
2 print(genList());
3 print(genList2());
4}
5
6Iterable<int> genList({int max = 10}) sync* {
7 var i = 0;
8 while (i < max) {
9 yield i;
10 i++;
11 }
12}
13
14Iterable<int> genList2({int max = 10}) {
15 var list = <int>[];
16 var i = 0;
17 while (i < max) {
18 list.add(i);
19 i++;
20 }
21 return list.map((i) => i);
22}
async*
这个返回值是一个 Stream
1main(List<String> arguments) {
2 print(genList());
3 print(genList2());
4
5 genStream().listen((data) {
6 print("stream1 : $data");
7 });
8
9 genStream2().listen((data) {
10 print("stream2 : $data");
11 });
12}
13
14
15Stream<int> genStream({int max = 10}) async* {
16 int i = 0;
17 while (i < max) {
18 yield i;
19 await Future.delayed(Duration(milliseconds: 300));
20 i++;
21 }
22}
23
24Stream<int> genStream2({int max = 10}) {
25 StreamController<int> controller = StreamController();
26
27 Future<void>.delayed(Duration.zero).then((_) async {
28 int i = 0;
29 while (i < max) {
30 controller.add(i);
31 await Future.delayed(Duration(milliseconds: 300));
32 i++;
33 }
34 controller.close();
35 });
36
37 return controller.stream;
38}
两种写法达到了一样的效果,但是生成器函数代码会更加简洁一些
执行结果如下
yield*
在生成器函数中还有一个关键字 yield*
这个关键字是结合递归使用的,可以配合sync*
也可以配合async*
结合 sync*
1main(List<String> arguments) {
2 var r = naturalsDownFrom(10);
3 print(r); //(10, 9, 8, 7, 6, 5, 4, 3, 2, 1)
4
5 r = naturalsDownWithNormal(10);
6 print(r); //(10, 9, 8, 7, 6, 5, 4, 3, 2, 1)
7}
8
9Iterable<int> naturalsDownFrom(int n) sync* {
10 if (n > 0) {
11 yield n;
12 yield* naturalsDownFrom(n - 1);
13 }
14}
15
16Iterable<int> naturalsDownWithNormal(int n) {
17 var list = <int>[];
18 if (n > 0) {
19 list.add(n);
20 var r = naturalsDownWithNormal(n - 1);
21 list.addAll(r);
22 }
23 return list.map((v) => v);
24}
结合 async*
1
2main(List<String> arguments){
3 naturalsStreamDownFrom(10).listen((data) {
4 print("data = $data");
5 });
6
7}
8
9Stream<int> naturalsStreamDownFrom(int n) async* {
10 if (n > 0) {
11 yield n;
12 yield* naturalsStreamDownFrom(n - 1);
13 }
14}
输出结果
1data = 10
2data = 9
3data = 8
4data = 7
5data = 6
6data = 5
7data = 4
8data = 3
9data = 2
10data = 1
常规写法分开写
1main(List<String> arguments) {
2 naturalsStreamDownWithNormal(10).listen((data) {
3 print("data2 = $data");
4 });
5}
6
7
8Stream<int> naturalsStreamDownWithNormal(int n) {
9 var controller = StreamController<int>();
10 if (n > 0) {
11 controller.add(n);
12 naturalsStreamDownWithNormal(n - 1).listen((data) {
13 controller.add(data);
14 });
15 }
16 return controller.stream;
17}
1data2 = 10
2data2 = 9
3data2 = 8
4data2 = 7
5data2 = 6
6data2 = 5
7data2 = 4
8data2 = 3
9data2 = 2
10data2 = 1
这里常规的写法也比较复杂,而且还有 controller 不关闭的可能
还需要注意一下 streamController 的关闭
需要修改如下
1
2Stream<int> naturalsStreamDownWithNormal(int n) {
3 var controller = StreamController<int>();
4 if (n > 0) {
5 controller.add(n);
6 naturalsStreamDownWithNormal(n - 1).listen((data) {
7 controller.add(data);
8 }, onDone: () {
9 print("close controller = $n");
10 controller.close();
11 });
12 } else {
13 controller.close();
14 }
15 return controller.stream;
16}
这里加了一个 print 输出
1close controller = 1
2data2 = 10
3close controller = 2
4data2 = 9
5close controller = 3
6data2 = 8
7close controller = 4
8data2 = 7
9close controller = 5
10data2 = 6
11close controller = 6
12data2 = 5
13close controller = 7
14data2 = 4
15close controller = 8
16data2 = 3
17close controller = 9
18data2 = 2
19close controller = 10
20data2 = 1
日志是这样的,递归调用,结束后递归关闭
官方的说法是,使用yield*会有性能优化,所以还是建议使用生成器函数
后记
粗略的分析了一下生成器函数,记录下,为了以后的朋友能看到,同时最重要的是记录自己的学习过程
以上