返回选项时 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"
}
我已经定义了下面的对象。但是我不明白为什么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
:
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"
}