Flutter/Dart学習中です。 Iterator の一つである where
を見ていたところこの記載があったので咀嚼してみます。
Creates a new lazy Iterable with all elements that satisfy the predicate test.
The matching elements have the same order in the returned iterable as they have in iterator.
This method returns a view of the mapped elements. As long as the returned Iterable is not iterated over, the supplied function test will not be invoked. Iterating will not cache results, and thus iterating multiple times over the returned Iterable may invoke the supplied function test multiple times on the same element.
述語テストを満たすすべての要素を持つ新しい遅延Iterableを作成します。
マッチする要素は、返されるイテレート可能の中では、イテレータの中と同じ順序になります。
このメソッドは、マップされた要素のビューを返します。返された Iterable が反復処理されない限り、与えられた関数テストは起動されません。イテレートしても結果はキャッシュされないので、返された Iterable を複数回イテレートすると、同じ要素に対して複数回関数テストが実行される可能性があります。
where method - Iterable class - dart:core library - Dart API
void main() { int counter = 0; final numbers = <int>[1, 2, 3, 5, 6, 7]; var result = (){ return numbers.where((n) { counter++; return n < 5; }); }(); // (1, 2, 3) print("--before run--"); print("counter: $counter"); print(""); print("--first time--"); print("result: $result"); print("counter: $counter"); print(""); print("--second time--"); print("result: $result"); print("counter: $counter"); }
<int>[1, 2, 3, 5, 6, 7];
から 5未満の値をとりだす処理をかきました。
これを実行するとこうなります。
--before run-- counter: 0 --first time-- result: (1, 2, 3) counter: 6 --second time-- result: (1, 2, 3) counter: 12
counter の値が2回目は倍になっていますね。これは result
を2回呼び出しているためです。
ドキュメントによるとイテレーターは遅延実行されるため、result
を呼び出したタイミングで処理が行われるので呼び出す都度評価されます。
一方で result をこのような形にかえると一度しか実行されませんし、result
を呼び出す前にすでに処理が確定しています。
void main() { int counter = 0; final numbers = <int>[1, 2, 3, 5, 6, 7]; List<int> result = (){ List<int> ret = []; for (final n in numbers) { counter++; if (n < 5) ret.add(n); } return ret; }(); // (1, 2, 3) print("--before run--"); print("counter: $counter"); print(""); print("--first time--"); print("result: $result"); print("counter: $counter"); print(""); print("--second time--"); print("result: $result"); print("counter: $counter"); }
--before run-- counter: 6 --first time-- result: [1, 2, 3] counter: 6 --second time-- result: [1, 2, 3] counter: 6
もしくは toList
を呼び出し Iterator から List に変えることで遅延処理を toList
で確定させることもできます。
void main() { int counter = 0; final numbers = <int>[1, 2, 3, 5, 6, 7]; var result = (){ return numbers.where((n) { counter++; return n < 5; }).toList(); }(); // (1, 2, 3) print("--before run--"); print("counter: $counter"); print(""); print("--first time--"); print("result: $result"); print("counter: $counter"); print(""); print("--second time--"); print("result: $result"); print("counter: $counter"); }