返回选项时 mapValues 中的奇怪行为

Strange behaviour in mapValues when returning an option

我已经定义了下面的对象。但是我不明白为什么mapValues body只在test1中执行。 IE。为什么输出:

Calling test1

Calling test2

Mapping: One

Mapping: Two

Mapped: Map(1 -> Xx, 2 -> Xx)

我已经用 scala 2.10 和 2.11 测试过,结果相同。

object Test {

    def test1: Option[String] = {

        val map = Map(1 -> "One", 2 -> "Two")
        val mapped = map.mapValues { v =>
            println("Mapping: " + v)
            "Xx"
        }
        None
    }

    def test2: Option[String] = {

        val map = Map(1 -> "One", 2 -> "Two")
        val mapped = map.mapValues { v =>
            println("Mapping: " + v)
            "Xx"
        }
        println("Mapped: " + mapped)
        None
    }



    def main(args: Array[String]): Unit = {

        println("Calling test1")
        test1
        println("Calling test2")
        test2
    }

}

mapValues实际上是returns一个view,所以结果是延迟计算的。来自 mapValues:

的 scaladoc

return a map view which maps every key of this map to f(this(key)). The resulting map wraps the original map without copying any elements.

例如:

val mapped = Map(1 -> "One", 2 -> "Two").mapValues { v =>
    println("Mapping: " + v)
    "Xx"
}

就其本身而言,它在声明时不会打印任何内容。但是一旦 mapped 被访问,就会计算值,并打印语句。 (事实上​​ ,每次访问 mapped 都会重新计算这些值

Test.test1 中,没有任何内容访问 mapped,因此永远不会计算值。

Test.test2 中,您正在打印 mapped,这会触发值的计算。

另一个答案解释了问题,但作为解决方案,如果你想要一个严格的地图,只需使用普通 map:

val m = Map(1 -> "One", 2 -> "Two")
val mapped = m.map { 
  case (k,v) => k -> {
    println("Mapping: " + v)
    "Xx"
  }
}

或者,您可以定义自己的扩展方法来执行您想要的操作:

import scala.collection.GenTraversableLike
import scala.collection.generic.CanBuildFrom
implicit class HasMapVals[T, U, Repr](val self: GenTraversableLike[(T, U), Repr]) extends AnyVal {
  def mapVals[R, That](f: U => R)(implicit bf: CanBuildFrom[Repr, (T, R), That]) = {
    self.map { case (k,v) => k -> f(v) }
  }
}

val m = Map(1 -> "One", 2 -> "Two")
val mapped = m.mapVals { v =>
  println("Mapping: " + v)
  "Xx"
}