yield* 是 Dart 语言(Flutter 使用 Dart)中的一个关键字,用于生成器函数 中,表示将另一个生成器中的所有值逐个产出。
一、yield* 的基本概念
生成器函数是可以多次返回值 的函数,使用 sync*(同步)或 async*(异步)标记。
// 同步生成器:返回 Iterable
Iterable<int> syncGenerator() sync* {
yield 1;
yield 2;
yield 3;
}
// 异步生成器:返回 Stream
Stream<int> asyncGenerator() async* {
yield 1;
yield 2;
yield 3;
}
2. yield vs yield*
| 关键字 | 作用 | 产出 |
|---|---|---|
yield |
产出一个值 | 单个值 |
yield* |
产出另一个生成器的所有值 | 多个值 |
// 使用 yield
Iterable<int> withYield() sync* {
yield 1;
yield 2;
yield 3;
}
// 产出:1, 2, 3
// 使用 yield*
Iterable<int> withYieldStar() sync* {
yield* [1, 2, 3]; // 展开列表中的所有值
}
// 产出:1, 2, 3(效果相同)
二、yield* 的语法和用法
1. 基本语法
// 同步生成器中使用 yield*
Iterable<T> generator() sync* {
yield* otherIterable; // 产出 otherIterable 中的所有元素
}
// 异步生成器中使用 yield*
Stream<T> asyncGenerator() async* {
yield* otherStream; // 产出 otherStream 中的所有事件
}
2. 实际示例
// 示例 1:展开列表
Iterable<int> flattenList() sync* {
yield* [1, 2, 3];
yield* [4, 5, 6];
}
void main() {
print(flattenList().toList()); // [1, 2, 3, 4, 5, 6]
}
// 合并多个数据源
Stream<int> mergeStreams() async* {
yield* Stream.fromIterable([1, 2, 3]);
yield* Stream.fromIterable([4, 5, 6]);
yield* Stream.fromIterable([7, 8, 9]);
}
// 使用
StreamSubscription? subscription;
subscription = mergeStreams().listen((value) {
print(value); // 1,2,3,4,5,6,7,8,9
});
四、yield* vs 其他方式
1. yield* vs for 循环
// 使用 yield*(简洁)
Iterable<int> withYieldStar() sync* {
yield* [1, 2, 3];
}
// 使用 for 循环(冗长)
Iterable<int> withForLoop() sync* {
for (var item in [1, 2, 3]) {
yield item;
}
}
// 效果完全相同,但 yield* 更简洁
2. yield* vs await for
// 异步生成器中使用 yield*
Stream<int> withYieldStar() async* {
yield* Stream.fromIterable([1, 2, 3]);
}
// 使用 await for(等效,但更冗长)
Stream<int> withAwaitFor() async* {
await for (var value in Stream.fromIterable([1, 2, 3])) {
yield value;
}
}
五、注意事项
1. 不能混用同步和异步
// 错误:同步生成器中不能使用异步源
Iterable<int> wrong() sync* {
yield* Stream.fromIterable([1, 2, 3]); // 编译错误!
}
// 正确:同步生成器只能用于同步源
Iterable<int> correct() sync* {
yield* [1, 2, 3]; // 正确
}
2. 类型必须匹配
// 错误:类型不匹配
Stream<String> wrong() async* {
yield* Stream.fromIterable([1, 2, 3]); // 编译错误!类型不匹配
}
// 正确:类型必须一致
Stream<int> correct() async* {
yield* Stream.fromIterable([1, 2, 3]); // 正确
}
六、对比表
| 特性 | yield |
yield* |
|---|---|---|
| 产出数量 | 单个值 | 多个值(展开另一个生成器) |
| 使用场景 | 产出一个值 | 委托给另一个生成器 |
| 递归支持 | 需要手动递归 | 天然支持递归 |
| 性能 | 直接产出 | 直接委托,无开销 |
| 代码简洁度 | 一般 | 高(避免嵌套循环) |
备注:
-
yield*用于将另一个生成器的所有值逐个产出 -
常用于递归遍历 、Stream 组合 、分页加载
-
比手动
for循环或await for更简洁 且高效 -
必须在同类型生成器 中使用(
sync*配sync*,async*配async*)