在一个案例类(或该对象的对象)上的scala方法(def)中的val只计算一次吗?

时间:2015-05-21 18:15:46

标签: scala

根据这个例子,对于每个类的实例,someValue的计算只运行一次?

case class MyThing {

  def myMethod {
    val someValue = 19 * 27
    someValue
  }

}

相同的规则是否适用于object

object MyObject {

  def myMethod {
    val someValue = 19 * 27
    someValue
  }

}

如果你有一个不可变的case类(当然,对象由于是单个实例而是不可变的),那么重新运行已经运行的计算是没有意义的,即使它们在类本身中使用了值(我正在考虑自定义hashCode计算(例如)。

编译器是否足够智能处理或者将val放在def之外会更好吗? (让它变得懒惰所以它只在需要时被调用......)

2 个答案:

答案 0 :(得分:2)

文字在编译时内联:

scala> object O { def f = 19*27 }
defined object O

scala> :javap -c O
Compiled from "<console>"
public class O$ {

  public int f();
    Code:
       0: sipush        513
       3: ireturn

  <snip>
}

通常,当没有涉及文字时,Scala编译器不会优化这种情况:

scala> object O { def f = g*h; def g = 19; def h = 27 }
defined object O

scala> :javap -c O
Compiled from "<console>"
public class O$ {

  public int f();
    Code:
       0: aload_0
       1: invokevirtual #17                 // Method g:()I
       4: aload_0
       5: invokevirtual #20                 // Method h:()I
       8: imul
       9: ireturn

  public int g();
    Code:
       0: bipush        19
       2: ireturn

  public int h();
    Code:
       0: bipush        27
       2: ireturn

  <snip>
}

当您编写def时,您的意思是def,即每次调用该方法时,都会评估其中的所有内容。任何应该缓存的东西都需要手动完成。

然而,在上面的示例中,JVM本身很可能会内联gh,结果是第一个和第二个示例将针对相同的机器代码进行优化。

答案 1 :(得分:0)

简单地说:不。

val仅评估一次。

每次都会评估

def

这是Scala语言中这些关键字之间的区别。

由于myMethod没有参数且不受副作用影响,因此应将其更改为val或更改为lazy val,以便仅在需要时运行。

使用intent进行编程而不是依赖编译器优化会更有效率。