简体   繁体   English

Scala 中的惰性求值、thunk 和函数闭包

[英]Lazy evaluation, thunk and function closure in Scala

case class Test[A](elem: () => A)

object Fun extends App {

  def test1(v: => Int): Test[Int] = Test(() => v)

  val a1 = test1({ println("hello"); 1 })
  val a2 = a1.elem() //echoes hello
  val a3 = a1.elem() //echoes hello

  def test2(v: => Int): Test[Int] = {
    lazy val y = v
    Test(() => y)
  }

  val b1 = test2({ println("hello"); 1 })
  val b2 = b1.elem() //echoes hello
  val b3 = b1.elem() //doesn't echo hello. Is function closure at work here?
}

Test is a case class that takes an object of type Function0[A] as constructor argument. Test 是一个 case 类,它将Function0[A]类型的对象作为构造函数参数。

test1 uses a non-strict parameter and returns an instance of Test[Int] . test1使用非严格参数并返回Test[Int]的实例。 when a1 is created, it gets elem = () => { println("hello"); 1 }a1创建时,它得到elem = () => { println("hello"); 1 } elem = () => { println("hello"); 1 } . elem = () => { println("hello"); 1 } . And so it makes sense when hello gets printed twice while a2 and a3 are created by applying elem.因此,当hello被打印两次而a2a3是通过应用 elem 创建时,这是有道理的。

test2 also uses a non-strict parameter and returns an instance of Test[Int] . test2还使用非严格参数并返回Test[Int]的实例。 when b1 is created, it gets elem = () => y .b1创建时,它得到elem = () => y The y is unevaluated and is bound to the caller - test2 . y未计算并且绑定到 caller- test2 When elem is applied to create b2 , through elem() , y gets evaluated (and thus prints hello ) and then caches the result which is 1 .elem用于创建b2 ,通过elem()y被评估(并因此打印hello ),然后缓存结果1 Subsequent call to elem() while creating b3 uses the evaluated value.创建b3elem()后续调用使用评估值。 However since y is not local to elem , the only way all this can work is through closure.然而,由于y不是elem本地的,所以所有这些都可以工作的唯一方法是通过闭包。

Is that accurate?那是准确的吗?

Note: I have gone through the example posted here : Scala lazy evaluation and apply function but it isn't exactly what I am trying to understand注意:我已经浏览了此处发布的示例: Scala 延迟评估和应用函数,但这并不是我想要理解的内容

You can see the implementation of captured elements using scalac -Vprint:_ .您可以使用scalac -Vprint:_查看捕获元素的实现。

In this case,在这种情况下,

    def test2(v: Function0): Test = {
      lazy <artifact> val y$lzy: scala.runtime.LazyInt = new scala.runtime.LazyInt();
      new Test({
        (() => Fun.this.$anonfun$test2$1(y$lzy, v))
      })
    };

The lazy local becomes heap-allocated, with a reference passed into the closure.惰性本地变为堆分配,并将引用传递到闭包中。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM