Scala 函数未被惰性地评估

Scala 函数未被惰性地评估,scala,lazy-evaluation,Scala,Lazy Evaluation,在下面的代码中,我将测试我对Scala惰性计算的理解 我试图在函数定义中只处理一次集合。但正如下面可以看到的,processMap被多个分层调用。不应该只调用一次吗 val a = Array( ("1" , "1") , ("2" , "2")) //> a : Array[(String, String)] = Array((1,1), (2,2)) def toLazyMapDef(aparam : Array[(String, String)]) = {

在下面的代码中,我将测试我对Scala惰性计算的理解

我试图在函数定义中只处理一次集合。但正如下面可以看到的,processMap被多个分层调用。不应该只调用一次吗

  val a = Array( ("1" , "1") , ("2" , "2"))       //> a  : Array[(String, String)] = Array((1,1), (2,2))

  def toLazyMapDef(aparam : Array[(String, String)]) = {
    lazy val toMap = processMap(aparam)
    toMap
  }                                               //> toLazyMapDef: (aparam: Array[(String, String)])scala.collection.immutable.Ma
                                                  //| p[String,String]
  def processMap(aparam : Array[(String, String)]) = {

    println("in processMap")
    aparam.toMap
  }                                               //> processMap: (aparam: Array[(String, String)])scala.collection.immutable.Map[
                                                  //| String,String]

  println(toLazyMapDef(a))                        //> in processMap
                                                  //| Map(1 -> 1, 2 -> 2)
  println(toLazyMapDef(a))                        //> in processMap
                                                  //| Map(1 -> 1, 2 -> 2)
  println(toLazyMapDef(a))                        //> in processMap
                                                  //| Map(1 -> 1, 2 -> 2)

这里,lazy val toMap是函数的内部变量。它不会在函数调用之间保留。这可能是一个更好的示例,我们将lazy val作为类成员,并且我们可以证明它只被计算一次:

case class LazyMapDemo(aparam : Array[(String, String)]) {
    lazy val toMap = processMap(aparam)
    def giveLazyMap = toMap
    def processMap(aparam : Array[(String, String)]) = {
      println("in processMap")
      aparam.toMap
   }
  }    

scala> val a = Array( ("1" , "1") , ("2" , "2"))
a: Array[(String, String)] = Array((1,1), (2,2))

scala> val ld = LazyMapDemo(a)
ld: LazyMapDemo = LazyMapDemo([Lscala.Tuple2;@63f5faaa)

scala> ld.toMap
in processMap
res0: scala.collection.immutable.Map[String,String] = Map(1 -> 1, 2 -> 2)

scala> ld.toMap // processMap not called
res1: scala.collection.immutable.Map[String,String] = Map(1 -> 1, 2 -> 2)

scala> ld.giveLazyMap // processMap not called
res2: scala.collection.immutable.Map[String,String] = Map(1 -> 1, 2 -> 2)

这里,lazy val toMap是函数的内部变量。它不会在函数调用之间保留。这可能是一个更好的示例,我们将lazy val作为类成员,并且我们可以证明它只被计算一次:

case class LazyMapDemo(aparam : Array[(String, String)]) {
    lazy val toMap = processMap(aparam)
    def giveLazyMap = toMap
    def processMap(aparam : Array[(String, String)]) = {
      println("in processMap")
      aparam.toMap
   }
  }    

scala> val a = Array( ("1" , "1") , ("2" , "2"))
a: Array[(String, String)] = Array((1,1), (2,2))

scala> val ld = LazyMapDemo(a)
ld: LazyMapDemo = LazyMapDemo([Lscala.Tuple2;@63f5faaa)

scala> ld.toMap
in processMap
res0: scala.collection.immutable.Map[String,String] = Map(1 -> 1, 2 -> 2)

scala> ld.toMap // processMap not called
res1: scala.collection.immutable.Map[String,String] = Map(1 -> 1, 2 -> 2)

scala> ld.giveLazyMap // processMap not called
res2: scala.collection.immutable.Map[String,String] = Map(1 -> 1, 2 -> 2)

谢谢,但是为什么您的版本会像预期的那样运行,而我的版本不会,因为版本之间的差异似乎是您已将逻辑封装在case类中,而在我的版本中,逻辑位于工作表中?我不明白你所说的在函数调用之间保留是什么意思?@blue sky在你的示例中,每当你调用toLazyMapDef时,一个新的惰性变量就会在函数调用后启动并销毁。它基本上是无用的。在@Ashalynd的示例中,lazy变量是类的一个成员,因此被保留,并且可以多次访问。谢谢,但是为什么您的版本表现得像预期的那样,而我的版本却没有。当版本之间的差异似乎是您将逻辑封装在一个case类中时,而在我的版本中,逻辑在工作表中?我不明白你所说的在函数调用之间保留是什么意思?@blue sky在你的示例中,每当你调用toLazyMapDef时,一个新的惰性变量就会在函数调用后启动并销毁。它基本上是无用的。在@Ashalynd的示例中,lazy变量是类的一个成员,因此被保留并可以多次访问。