我已经定义了下面的对象。但我不明白为什么mapValues主体只在test1中执行。即。为什么输出:
调用test1
调用test2
映射:一个
映射:两个
映射:映射(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
}
}
答案 0 :(得分:2)
mapValues
实际上会返回view,因此结果会被懒惰地计算出来。来自mapValues
的scaladoc:
返回地图视图,将此地图的每个键映射到f(此(键))。生成的地图包装原始地图而不复制任何元素。
例如:
val mapped = Map(1 -> "One", 2 -> "Two").mapValues { v =>
println("Mapping: " + v)
"Xx"
}
在它自己时,这将在宣布时不打印任何内容。但是只要访问mapped
,就会计算出值,并打印语句。 (事实上,在您访问mapped
的每个时间将重新计算值
在Test.test1
中,没有任何内容可以访问mapped
,因此永远不会计算这些值。
在Test.test2
中,您打印出mapped
,这会触发值的计算。
答案 1 :(得分:1)
另一个答案解释了这个问题,但作为一个解决方案,如果你想要一个严格的地图,只需使用普通的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"
}