Stream 基础
本课属于 Coddy Dart 学习旅程的“面向对象编程”单元。第 77 课,共 110 课。
Future 会返回单个值,而 Stream 会随时间返回一系列值。你可以把它想象成一根管道,它能发出多条数据,非常适合处理事件、实时更新或逐条处理数据。
你可以使用 Stream.fromIterable() 创建简单的流,也可以使用带有 async* 和 yield 的异步生成器函数:
Stream<int> countToThree() async* {
yield 1;
yield 2;
yield 3;
}
Future<void> main() async {
await for (var number in countToThree()) {
print(number);
}
}
// 输出:1, 2, 3async* 关键字用于标记返回 Stream 的函数,而 yield 会发出每个值。要使用这个流,请使用 await for,它会在每个值到达时进行处理。
你也可以使用 listen() 方法监听流,该方法接受一个回调函数:
Stream<String> greetings() async* {
yield 'Hello';
yield 'Hi';
yield 'Hey';
}
void main() {
greetings().listen((message) {
print(message);
});
}与 Future 的关键区别在于:Future 只会完成一次,并返回一个值;而 Stream 可以在完成前发出多个值。因此,Stream 非常适合处理持续产生的数据,例如用户交互、传感器读数或分块到达的数据。
挑战
简单让我们使用流来构建一个倒计时器系统,随着时间推移发出多个值!你将创建一个类,生成一系列倒计时数字,了解流如何传递多个值,而不只是一个值。
你将把代码整理到两个文件中:
countdown.dart:创建一个生成倒计时流的Countdown类。这个类应包含:- 一个
start字段(int),用于存储倒计时的起始数字 - 一个接收起始数字的构造函数
- 一个返回
Stream<int>的countDown()方法。使用async*和yield发出从start到0(包含0)的数字 - 一个返回
Stream<String>的countDownWithMessage()方法。对于从start到1的每个数字,该方法都应按'T-minus [number]'的格式发出字符串,然后将'Liftoff!'作为最后一个值发出
- 一个
main.dart:导入倒计时文件,并演示这两个流方法。你的 main 函数应为 async,并且:- 创建一个从
3开始的Countdown实例 - 打印
Number countdown: - 使用
await for遍历countDown(),并打印每个数字 - 打印一个空行
- 打印
Launch sequence: - 使用
await for遍历countDownWithMessage(),并打印每条消息
- 创建一个从
注意,每条 yield 语句都会通过流发出一个值,而 await for 会在每个值到达时对其进行处理。与只传递一个结果的 Future 不同,你的流会按顺序发出多个值!
预期输出:
Number countdown:
3
2
1
0
Launch sequence:
T-minus 3
T-minus 2
T-minus 1
Liftoff!亲手试试
import 'countdown.dart';
Future<void> main() async {
// TODO: 创建一个从 3 开始的 Countdown 实例
// TODO: 打印 'Number countdown:'
// TODO: 使用 await for 遍历 countDown(),并打印每个数字
// TODO: 打印一个空行
// TODO: 打印 'Launch sequence:'
// TODO: 使用 await for 遍历 countDownWithMessage(),并打印每条消息
}
这节课包含一个小测验。开始学习即可作答,并记录你的进度。
面向对象编程中的所有课
自己练习: Dart 在线编译器