惰性val类变量是如何在Scala2.10中实现的



这个问题的答案是Scala懒惰val的(隐藏的)代价是什么?展示了它们是如何在Scala 2.7中实现的。但正如评论所说,从那以后,情况肯定发生了变化,所以我很好奇,lazy val类变量的当前(2.10)实现是什么?

用scala 2.10.2:编译

class Foo {
  lazy val bar = math.pow(5, 3)
}

然后用JD-GUI:反编译结果

import scala.math.package.;
import scala.reflect.ScalaSignature;
@ScalaSignature(bytes="0601e1A!01020113t31ai\81303rtq01P3naRLhh0101240501101CA04133305A!"A050213M3427r\1n05-A!AB!osJ+grC0316012105a"0104=S:LGO20130237A210103A070205!A!0301EC0223051#A02cCJ,220106t0317UI!A060503r21{WO317f21!A0201#A!B23!2201022be0202")
public class Foo {
    private double bar;
    private volatile boolean bitmap$0;
    private double bar$lzycompute() {
        synchronized (this) { 
            if (!this.bitmap$0) { 
                this.bar = package..MODULE$.pow(5.0D, 3.0D); 
                this.bitmap$0 = true; 
            } 
            return this.bar; 
        }  
    } 
    public double bar() { 
        return this.bitmap$0 ? this.bar : bar$lzycompute(); 
    }
}

编辑-以下是三个字段的情况:

class Foo {
  lazy val a = math.pow(5, 1)
  lazy val b = math.pow(5, 2)
  lazy val c = math.pow(5, 3)
}

解压缩:

import scala.math.package.;
import scala.reflect.ScalaSignature;
@ScalaSignature(bytes="0601052A!01020113t31ai\81303rtq01P3naRLhh0101240501101CA04133305A!"A050213M3427r\1n05-A!AB!osJ+grC0316012105a"0104=S:LGO20130237A210103A070205!A!0301EC0223051#A01b+05!02CA042623t102B0104E_V24G.3205t101At21)Q05)052121rt05t501A)31!C01'05t!r03053501!05t25)032503t21070503053701!25r21"01240305310702032101210305132502130205r0403")
public class Foo {
    private double a;
    private double b;
    private double c;
    private volatile byte bitmap$0;
    private double a$lzycompute() {
        synchronized (this) {
            if ((byte)(this.bitmap$0 & 0x1) == 0) {
                this.a = package..MODULE$.pow(5.0D, 1.0D); 
                this.bitmap$0 = ((byte)(this.bitmap$0 | 0x1)); 
            } 
            return this.a;
        }  
    } 
    private double b$lzycompute() { 
        synchronized (this) {
            if ((byte)(this.bitmap$0 & 0x2) == 0) {
                this.b = package..MODULE$.pow(5.0D, 2.0D); 
                this.bitmap$0 = ((byte)(this.bitmap$0 | 0x2)); 
            } 
            return this.b; 
        }  
    } 
    private double c$lzycompute() { 
        synchronized (this) {
            if ((byte)(this.bitmap$0 & 0x4) == 0) {
                this.c = package..MODULE$.pow(5.0D, 3.0D); 
                this.bitmap$0 = ((byte)(this.bitmap$0 | 0x4)); 
            } 
            return this.c;
        }
    }
    public double a() {
        return (byte)(this.bitmap$0 & 0x1) == 0 ? a$lzycompute() : this.a;
    }
    public double b() { 
        return (byte)(this.bitmap$0 & 0x2) == 0 ? b$lzycompute() : this.b; 
    } 
    public double c() { 
        return (byte)(this.bitmap$0 & 0x4) == 0 ? c$lzycompute() : this.c;
    }
}

更新Scala 2.12.1(三年后的2016年12月)。

在PR 5294(字段阶段完全扩展延迟val和模块)之后,您可以在提交743f0d2:中读取

懒惰的val没有本地

现在synchronized被专门擦除以避免拳击,我们可以放弃这项工作。

请注意,这确实在慢速路径上添加了一个额外的cast和getter调用,但这可能无关紧要。

class C { def foo = {lazy val x = {println("a"); "A" }; x } }

变为:

def foo(): String = {
  lazy <artifact> val x$lzy: scala.runtime.LazyRef[String] = new scala.runtime.LazyRef[String]();
  <artifact> private def x$lzycompute(): String =
    x$lzy.synchronized[String]{
      if (x$lzy.initialized())
        x$lzy.value() // NOTE: gets an `.asInstanceOf[String]` after erasure
      else
        {
          x$lzy.value_=({
            scala.Predef.println("a");
            "A"
          });
          x$lzy.initialized_=(true);
          x$lzy.value() // NOTE: gets an `.asInstanceOf[String]` after erasure
        }
    }
  lazy def x(): String =
    if (x$lzy.initialized())
      x$lzy.value() // NOTE: gets an `.asInstanceOf[String]` after erasure
    else
      x$lzycompute();
  x()
}