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

问题描述 投票:14回答:3

在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方法。

scala foreach scala-collections side-effects
3个回答
13
投票

我可以想到几个动机:

  1. foreachUnit类型的方法的最后一行时,你的编译器不会发出警告,但会使用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)

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

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)
© www.soinside.com 2019 - 2024. All rights reserved.