Scala:“map”vs“foreach” - 有没有理由在实践中使用“foreach”?

时间:2014-09-10 00:00:06

标签: scala foreach scala-collections side-effects

在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的使用是合理的,但据我所知,一个人特别需要偶然发现{{1}正常

(**)如果一个人不使用一个集合,但正在写一个集合,那么很快就会发现LazyMap理解语法语法实际上是一种语法糖,可以生成" foreach"调用,即这两行生成完全等效的代码:

for

因此,如果有人关心使用带有for (element <- myCollection) { doStuffWithElement(element); } myCollection.foreach { element => doStuffWithElement(element); } 语法的集合类的其他人,可能仍然希望实现for方法。

3 个答案:

答案 0 :(得分:13)

我可以想到几个动机:

  1. foreach是类型为Unit的方法的最后一行时,您的编译器不会发出警告,但会使用map(并且您需要-Ywarn-value-discard上)。有时您使用warning: a pure expression does nothing in statement position; you may be omitting necessary parentheses获得map但不会使用foreach
  2. 一般可读性 - 读者可以知道您在不返回某些内容的情况下改变某些状态,但如果使用map则需要更多的认知资源来理解相同的操作
  3. 继续1.您还可以在传递命名函数时进行类型检查,然后进入mapforeach
  4. 使用foreach无法构建新列表,因此效率更高(感谢@Vishnu)

答案 1 :(得分:6)

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

答案 2 :(得分:4)

如果可以优化建造机械,我会留下深刻的印象。

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)