はじめに
環境
-
macOS Sonoma (14.1.2)
-
Dart SDK version: 3.3.0
本題
-
Stream を返す関数 countStream は main 関数から呼び出された直後では関数内の処理が実行されず sumStream 関数で await for を使用して Stream を処理した時に Stream を返す関数 countStream 内の処理が実行されている
-
試しに Stream を処理する関数 sumStream を呼び出さないように変更した時に Stream を返す関数 countStream 内の処理が実行されなかった
-
yield(生じる)によって発生した値を await for で処理している
-
yield によって値が発生しなくなり Stream を返す関数の処理が終わった時点で await for の処理も終了する
実行プログラム
Future<int> sumStream(Stream<int> stream) async {
print('sumStream - start');
var sum = 0;
await for (final value in stream) {
print('await for - start : ${value}');
sum += value;
print('await for - end : ${value}');
}
print('sumStream - end');
return sum;
}
Stream<int> countStream(int to) async* {
print('countStream - start');
for (int i = 1; i <= to; i++) {
print('yield - start : ${i}');
yield i;
print('yield - end : ${i}');
}
print('countStream - end');
}
void main() async {
print('call countStream');
var stream = countStream(3);
print('call sumStream');
var sum = await sumStream(stream);
print(sum); // 55
}
出力結果
call countStream
call sumStream
sumStream - start
countStream - start
yield - start : 1
await for - start : 1
await for - end : 1
yield - end : 1
yield - start : 2
await for - start : 2
await for - end : 2
yield - end : 2
yield - start : 3
await for - start : 3
await for - end : 3
yield - end : 3
countStream - end
sumStream - end
6
Stream は 2 種類
Single subscription streams
ファイル読み込みや Web リクエストを表していて最初から最後まで欠損なく chunk を読み出す必要がある。途中から購読しても意味が無くて一度のみ購読できる。
Broadcast streams
マウスイベントなどを表す。途中から購読するこもとできる。
引っかかった箇所
[firstWhere method](https://api.flutter.dev/flutter/dart-async/Stream/firstWhere.html)は最初に test にマッチする要素が見つかった時に Stream の購読をキャンセルする。いわゆる、Single subscription streams であり、以後、参照元の Stream に変更があっても変更を通知しなくなるので注意が必要になる。
Stream の再生成
-
map や where といった備え付けの関数を使用して既存の Stream を新たな Stream に変換できる
-
用途に合う変換ヘルパーがなかった場合でも 変換関数 を自前で実装できる
-
await for で既存の Stream を処理しつつ yeild で Stream を返せば自前で実装できる
参考記事
dart.dev、 「Asynchronous programming: Streams」、 2024/04/15、 https://dart.dev/tutorials/language/streams、 (2024/04/15)