为什么 map 不起作用但 foreach 可以?

Why is map not working but foreach is?

这个forEach工作得很好

var newMarkers = new List<Marker>();
providers.forEach((p) {
  var marker = markerFrom(p);
  newMarkers.add(marker);
  print("got one");
});

_markers = newMarkers;

但是这个 mapforEach 放在完全相同的位置时永远不会被调用:

_markers = providers.map((p) => markerFrom(p));

此外,这是 markerFrom 方法:

  Marker markerFrom(FoodProvider provider) {
  var marker = new Marker(new MarkerOptions()
    ..map = _map
    ..position = new LatLng(provider.latitude, provider.longitude)
    ..title = provider.name
    ..icon = 'http://maps.google.com/mapfiles/ms/icons/red-dot.png'
  );

  var infoWindow = new InfoWindow(new InfoWindowOptions()..content = marker.title);

  marker.onClick.listen((e) {
    infoWindow.open(_map, marker);
  });

  return marker;
}

Iterable 上的 map 函数是 lazy。它只是围绕原始 Iterable 创建了一个包装器,但在您开始迭代之前它实际上并没有做任何事情。

这是一件好事,即使如果您习惯了来自其他语言的热切map 功能,这可能会让您感到惊讶。这意味着您可以组合对可迭代对象的操作,例如:

listOfStrings
    .map((x) => complicatedOperationOnString(x))
    .take(2)
    .forEach(print);

这只对前两个字符串进行了复杂的操作。

如果你想要一个标记列表,你需要在 map:

之后调用 toList
_markers = providers.map(markerFrom).toList();

一般来说,当传递给 map 的函数具有您希望只发生一次的副作用时,您应该非常小心。如果你多次重复 map 的结果,每次都会发生这种效果,所以如果你这样做:

_markers = providers.map(markerFrom);
int count = _markers.length;
_markers.forEach((marker) { doSomething(marker); });

你会 副作用发生两次的风险,一次是 length,一次是 forEach,两者都会重复 _markers。 它并不总是发生(一些可迭代对象知道它们的 length 而无需实际迭代),但这始终是一种风险。在这些情况下,如果副作用是您唯一想要的,请使用 forEach,或者立即执行 toList 以强制执行所有操作,然后只查看之后的结果列表。