在Scala集合中,如果想要迭代一个集合(没有返回结果,即对集合的每个元素做一个副作用),它可以用
final def foreach(f: (A) ⇒ Unit): Unit
要么
final def map[B](f: (A) ⇒ B): SomeCollectionClass[B]
除了可能的延迟映射(*)之外,从最终用户的角度来看,我发现这些调用没有差异:
myCollection.foreach { element =>
doStuffWithElement(element);
}
myCollection.map { element =>
doStuffWithElement(element);
}
鉴于我可以忽略哪些地图输出。当map
似乎包含foreach
的所有功能时,我想不出为什么存在和使用两种不同方法的任何具体原因,事实上,如果智能编译器和VM不会给我留下深刻的印象优化出该集合对象的创建,因为它没有被分配给任何东西,或者在任何地方读取或使用。
所以,问题是 - 我是对的 - 并且没有理由在一个代码中的任何地方调用foreach
吗?
笔记:
(*)懒惰的映射概念,as throughly illustrated in this question,可能会改变一些事情,并证明使用foreach
,但据我所知,一个人特别需要偶然发现一个LazyMap
,正常
(**)如果一个人没有使用集合,而是写一个集合,那么很快就会发现for
理解语法语法实际上是生成“foreach”调用的语法糖这一事实,即这两行生成完全等效的代码:
for (element <- myCollection) { doStuffWithElement(element); }
myCollection.foreach { element => doStuffWithElement(element); }
因此,如果一个人关心使用for
语法的集合类的其他人,可能仍然想要实现foreach
方法。
我可以想到几个动机:
foreach
是Unit
类型的方法的最后一行时,你的编译器不会发出警告,但会使用map
(你需要使用-Ywarn-value-discard
)。有时你使用warning: a pure expression does nothing in statement position; you may be omitting necessary parentheses
获得map
但不会使用foreach
。map
,读者可以知道您在不返回某些内容的情况下改变某些状态,但需要更多的认知资源来理解相同的操作map
和foreach
foreach
不会构建新的列表,因此效率会更高(感谢@Vishnu)scala> (1 to 5).iterator map println
res0: Iterator[Unit] = non-empty iterator
scala> (1 to 5).iterator foreach println
1
2
3
4
5
如果建造机械可以优化,我会留下深刻的印象。
scala> :pa
// Entering paste mode (ctrl-D to finish)
implicit val cbf = new collection.generic.CanBuildFrom[List[Int],Int,List[Int]] {
def apply() = new collection.mutable.Builder[Int, List[Int]] {
val b = new collection.mutable.ListBuffer[Int]
override def +=(i: Int) = { println(s"Adding $i") ; b +=(i) ; this }
override def clear() = () ; override def result() = b.result() }
def apply(from: List[Int]) = apply() }
// Exiting paste mode, now interpreting.
cbf: scala.collection.generic.CanBuildFrom[List[Int],Int,List[Int]] = $anon$2@e3cee7b
scala> List(1,2,3) map (_ + 1)
Adding 2
Adding 3
Adding 4
res1: List[Int] = List(2, 3, 4)
scala> List(1,2,3) foreach (_ + 1)