▩Dart-生成器函数


当你需要延迟生成(lazily produce)一系列值时,可以考虑使用 生成器函数

类别关键字返回类型搭档
多元素同步sync*Iterable<T>yield、yield*
单元素异步asyncFuture<T>await
多元素异步async*Stream<T>yield、yield* 、await

我们可以看到,sync*返回肯定是一个Iterable对象;async返回肯定是一个Future对象;async*返回肯定是一个Stream对象。

零、yield与yield*关键字

yield用于从异步或同步生成器发出值。
yield从 Iterable 或 Stream 返回值。
yield表达式的值:是下一个iter.next的参数值。

yield*(发音为:yield-each)语句。yield后面的表达式必须表示另一个(子)序列。yield所做的是将子序列的所有元素插入到当前正在构造的序列中,就好像每个元素都有一个单独的yield一样。
yield*表达式的值:是yield*后的iterable在done为true时的value值。它将调用委托给另一个生成器,在该生成器停止生成值后,它会继续生成自己的值。
yield*可用于递归调用其 Iterable 或 Stream 函数。

示例:(多元素异步,搭配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 // 过1秒后输出
2 // 再过1秒后输出
3 // 再过1秒后输出

forEach()方法原型:
void forEach(void action(E element)) {
      for (E element in this) action(element);
}

示例:(多元素异步,搭配yield each)

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 // 过1秒后输出
2 // 再过1秒后输出
1 // 再过1秒后输出

一、多元素同步[生成器]
  1. 函数体标记 sync*, 使用 yield 语句来传递值。
    (👿 的码为\u{1f47f}。下面是使用多元素同步生成器生成后10个emoji。)
Iterable<String> getEmoji(int count) sync* {
  Runes first = Runes('\u{1f47f}');
  for (int i = 0; i < count; i++) {
    yield String.fromCharCodes(first.map((e) => e + i));
  }
}
main() {
  getEmoji(5).forEach(print);
}
👿
💀
💁
💂
💃

map()方法原型:
Iterable<T> map<T>(T toElement(E e))
等价于:
Iterable<T> map<T>(T toElement(E e)) sync* {
    for (var value in this) {
        yield toElement(value);
    }
}
这个迭代器的当前元素被toElement()方法修改。
返回一个新的惰性Iterable,其中包含通过按迭代顺序对该Iterable的每个元素调用toElement创建的元素。

  1. 使用sync*yield*
Iterable<String> getEmoji(int count) sync* {
  Runes first = Runes('\u{1f47f}');
  for (int i = 0; i < count; i++) {
    yield String.fromCharCodes(first.map((e) => e + i));
  }
}
Iterable<String> getEmojiWithTime(int count) sync* {
  yield* getEmoji(count).map((e) => '$e -- ${DateTime.now().toIso8601String()}');
}
main() {
  getEmojiWithTime(5).forEach(print);
}
👿 -- 2022-01-24T04:15:00.328843
💀 -- 2022-01-24T04:15:00.331835
💁 -- 2022-01-24T04:15:00.331835
💂 -- 2022-01-24T04:15:00.331835
💃 -- 2022-01-24T04:15:00.331835
二、单元素异步[生成器]

async是一个dart语法关键字。它标注在函数体{之前,其方法必须返回一个 Future<T>对象。
对于耗时操作,通常用Future<T>对象异步处理。

Future<String> fetchEmoji(int count) async {
  Runes first = Runes('\u{1f47f}');
  await Future.delayed(Duration(seconds: 2));//模拟耗时
  print('加载结束--${DateTime.now().toIso8601String()}');
  return String.fromCharCodes(first.map((e) => e + count));
}
main() {
  print('程序开启--${DateTime.now().toIso8601String()}');
  fetchEmoji(1).then(print);
}
程序开启--2022-01-24T04:22:59.952230
加载结束--2022-01-24T04:23:01.969479
💀
三、多元素异步[生成器]
  1. 使用async*yield + await
Future<String> fetchEmoji(int count) async {
  Runes first = Runes('\u{1f47f}');
  await Future.delayed(Duration(seconds: 1));//模拟耗时
  print('Load done--${DateTime.now().toIso8601String()}');
  return String.fromCharCodes(first.map((e) => e + count));
}
Stream<String> fetchEmojis(int count) async* {
  for (int i = 0; i < count; i++) {
    yield await fetchEmoji(i);
  }
}
main() {
  fetchEmojis(5).listen(print);
}
Load done--2022-01-24T04:40:36.343804
👿
Load done--2022-01-24T04:40:37.363934
💀
Load done--2022-01-24T04:40:38.370935
💁
Load done--2022-01-24T04:40:39.382114
💂
Load done--2022-01-24T04:40:40.395005
💃

A.去掉yield后面的await,编译报错:

The type ‘Stream<Future<String>>’ implied by the ‘yield’ expression must be assignable to ‘Stream<String>’.
类型‘Stream<Future<String>>’被‘yield’表达式暗示必须可被赋值给‘Stream<String>’。
B.去掉await前面的yield,打印输出:

Load done--2022-01-24T04:40:36.343804
Load done--2022-01-24T04:40:37.363934
Load done--2022-01-24T04:40:38.370935
Load done--2022-01-24T04:40:39.382114
Load done--2022-01-24T04:40:40.395005

yield用于从生成器发出值,没有yield,就不传递值,所以就没有可打印的字符图标了。

  1. 使用async*yield*await
Future<String> fetchEmoji(int count) async {
  Runes first = Runes('\u{1f47f}');
  await Future.delayed(Duration(seconds: 1));//模拟耗时
  return String.fromCharCodes(first.map((e) => e + count));
}
Stream<String> fetchEmojis(int count) async* {
  for (int i = 0; i < count; i++) {
    yield await fetchEmoji(i);
  }
}
Stream<String> getEmojiWithTime(int count) async* {
  yield* fetchEmojis(count).map((e) => '$e -- ${DateTime.now().toIso8601String()}');
}
main() {
  getEmojiWithTime(5).listen(print);
}
👿 -- 2022-01-24T04:34:53.499813
💀 -- 2022-01-24T04:34:54.513705
💁 -- 2022-01-24T04:34:55.524728
💂 -- 2022-01-24T04:34:56.532653
💃 -- 2022-01-24T04:34:57.543451
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

itzyjr

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值