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

时间:2015-01-13 18:12:50

标签: scala

我已经定义了下面的对象。但我不明白为什么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
    }

}

2 个答案:

答案 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"
}