2013-07-14 50 views
5

有一个question问关于lazy val的实现,如果它们是类变量的话。如何实现当地变量,例如在Scala的本地懒惰变量是如何实现的?

def foo[A](a: => A) = { 
    lazy val x: A = a 
    // return something that uses x 
} 
+0

逻辑相同,但不需要同步。 –

+0

@RandallSchulz但是如果'x''逃脱它的范围,就像[在这里]一样(https://github.com/scalaz/scalaz/blob/59bdfecdae88f8e166f8d39cd08879ed87f3db17/core/src/main/scala/scalaz/Name.scala#L39 )?然后它可以被多个线程访问。 –

+0

嗯......是的!在这种情况下,需要明确的同步。 –

回答

3

这有点低效率的方法,使用延迟瓦尔斯。原因是你实际上不能嵌套函数,因此名义上在堆栈上分配的懒惰位实际上需要堆在堆上。所以你必须创建至少一个额外的对象,事实证明,斯卡拉实际上创建了两个。

class Baz{ 
    def baz(i: => Int, b: Boolean) = { 
    lazy val j = i 
    if (b) j else 0 
    } 
} 

变成,除其他事项外

public int baz(scala.Function0, boolean); 
    Code: 
    0: new #12; //class scala/runtime/IntRef 
    3: dup 
    4: iconst_0 
    5: invokespecial #16; //Method scala/runtime/IntRef."<init>":(I)V 
    8: astore_3 
    9: new #18; //class scala/runtime/VolatileByteRef 
    12: dup 
    13: iconst_0 
    14: invokespecial #21; //Method scala/runtime/VolatileByteRef."<init>":(B)V 
    17: astore 4 
    19: iload_2 
    20: ifeq 34 
    23: aload_0 
    24: aload_1 
    25: aload_3 
    26: aload 4 
    28: invokespecial #25; //Method j$1:(Lscala/Function0;Lscala/runtime/IntRef; 
               Lscala/runtime/VolatileByteRef;)I 
    31: goto 35 
    34: iconst_0 
    35: ireturn 

IntRefVolatileByteRef创造?这些代替了通常只是处理懒惰价值的私人变数。现在,j$1,为处理lazy val的检索和/或创建而创建的访问器方法必须将这两个新创建的类作为参数(除了by-name函数)。

所以,虽然底层的机制是相同的,但实现的细节是不同的,并且比如果你已经有另外一个类来粘附变量的效率更低。