为什么这个惰性迭代解析不止一次?
Why is this lazy iterable resolving more than once?
我 运行 今天用一些生产代码解决了这个问题,并且能够用一个简单的 .toList()
修复它,在等待之前解析 lazyList,但我不明白为什么它会这样工作并且 仅 使用 Future.wait()
时这是怎么回事?为什么 lazyList 被解析了两次?
Play with it on DartPad(改变第3行doWait
的值,看到不同的结果)
代码
import 'dart:async';
void main() {
var executedTracker = [];
var source = ["a", "b", "c"];
List promises = source.map((item) async {
print('executing item $item${(executedTracker.contains(item) ? ' (again!? o_O)' : '')}'); executedTracker.add(item);
return (item*2);
});
Future.wait(promises).whenComplete(() {
print('--------\nAll promises complete.');
print('Processing ${promises.length} results...\n');
promises.forEach((promise) => null /* do a thing with the result*/);
});
}
输出
executing item a
executing item b
executing item c
All promises complete.
Processing 3 results...
executing item a (again!? o_O)
executing item b (again!? o_O)
executing item c (again!? o_O)
因为您迭代 promises
两次,一次在 Future.wait(promises)
中,一次在 promises.forEach(...)
中。
(你很幸运 promises.length
- 因为映射的可迭代对象知道它是基于列表的,所以它不会再次迭代来找到长度。)
一个mapped iterable的每次迭代都会重新迭代原来的iterable并再次执行map操作,这就是lazy transformation的意思。对于hugelyGiganticIterable.map(something).take(10).toList()
这样的情况,懒惰是必要的。如果它不是惰性的,它将对巨大的 iterable 中的所有元素执行映射(它甚至可以是无限的,iterables 可以是无限的,与列表不同)。
您可能想在真实示例中使用 Future.wait(promises)
操作的结果:
Future.wait(promises).then((items) {
print('--------\nAll promises complete.');
print('Processing ${items.length} results...\n');
items.forEach((item) => null /* do a thing with the *result* */);
});
如果您实际上并不想要 惰性行为,那么您应该热切地收集这些值。你这样做,例如,通过写作:
List promises = source.map((item) async {
...
}).toList(); // <-- notice the ".toList()"!
使用toList
强制计算可迭代对象的每个映射元素,消除惰性。
我 运行 今天用一些生产代码解决了这个问题,并且能够用一个简单的 .toList()
修复它,在等待之前解析 lazyList,但我不明白为什么它会这样工作并且 仅 使用 Future.wait()
时这是怎么回事?为什么 lazyList 被解析了两次?
Play with it on DartPad(改变第3行doWait
的值,看到不同的结果)
代码
import 'dart:async';
void main() {
var executedTracker = [];
var source = ["a", "b", "c"];
List promises = source.map((item) async {
print('executing item $item${(executedTracker.contains(item) ? ' (again!? o_O)' : '')}'); executedTracker.add(item);
return (item*2);
});
Future.wait(promises).whenComplete(() {
print('--------\nAll promises complete.');
print('Processing ${promises.length} results...\n');
promises.forEach((promise) => null /* do a thing with the result*/);
});
}
输出
executing item a
executing item b
executing item c
All promises complete.
Processing 3 results...
executing item a (again!? o_O)
executing item b (again!? o_O)
executing item c (again!? o_O)
因为您迭代 promises
两次,一次在 Future.wait(promises)
中,一次在 promises.forEach(...)
中。
(你很幸运 promises.length
- 因为映射的可迭代对象知道它是基于列表的,所以它不会再次迭代来找到长度。)
一个mapped iterable的每次迭代都会重新迭代原来的iterable并再次执行map操作,这就是lazy transformation的意思。对于hugelyGiganticIterable.map(something).take(10).toList()
这样的情况,懒惰是必要的。如果它不是惰性的,它将对巨大的 iterable 中的所有元素执行映射(它甚至可以是无限的,iterables 可以是无限的,与列表不同)。
您可能想在真实示例中使用 Future.wait(promises)
操作的结果:
Future.wait(promises).then((items) {
print('--------\nAll promises complete.');
print('Processing ${items.length} results...\n');
items.forEach((item) => null /* do a thing with the *result* */);
});
如果您实际上并不想要 惰性行为,那么您应该热切地收集这些值。你这样做,例如,通过写作:
List promises = source.map((item) async {
...
}).toList(); // <-- notice the ".toList()"!
使用toList
强制计算可迭代对象的每个映射元素,消除惰性。