简体   繁体   English

案例类(或与此相关的对象)上的 Scala 方法(def)中的 val 是否仅计算一次?

[英]Is a val in a scala method (def) on a case class (or an object for that matter) calculated only once?

As per this example will the calculation for someValue be ran only once for each instance of the class?根据这个例子,对于类的每个实例, someValue 的计算是否只运行一次?

case class MyThing {

  def myMethod {
    val someValue = 19 * 27
    someValue
  }

}

Would the same rules apply to an object相同的规则是否适用于object

object MyObject {

  def myMethod {
    val someValue = 19 * 27
    someValue
  }

}

If you have an immutable case class (and of course objects are immutable by virtue of being a single instance) then there is no sense in re-running calculations that have been ran, even if they use values in the class itself (I'm thinking of custom hashCode calculations for example).如果你有一个不可变的 case 类(当然对象是不可变的,因为它是单个实例)那么重新运行已经运行的计算是没有意义的,即使它们使用类本身中的值(我是例如,考虑自定义 hashCode 计算)。

Is the compiler smart enough to handle that or would it be better to place the val outside of the def?编译器是否足够聪明来处理这个问题,还是将 val 放在 def 之外会更好? (Making it lazy so it only gets called when needed...) (让它变得懒惰,所以它只在需要时才被调用......)

The literal is inlined at compile time:文字在编译时内联:

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>
}

Generally, the Scala compiler doesn't optimize such cases when there are no literals involved:通常,当不涉及文字时,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>
}

When you write def , then you mean def , ie every time you call the method everything in it is evaluated.当您编写def ,您的意思是def ,即每次调用该方法时,都会评估其中的所有内容。 Anything that should be cached needs to be done manually on your side.应该缓存的任何内容都需要在您身边手动完成。

In the above example however, it is very likely that the JVM itself will inline g and h , with the result that the first and the second example will be optimized to the same machine code.然而,在上面的例子中,JVM 本身很可能会内联gh ,结果第一个和第二个例子将被优化为相同的机器代码。

Simply put: No.简单地说:没有。

val is only evaluated once. val只计算一次。

def is evaluated every time. def每次都会被评估。

That is the difference between those keywords in the Scala language.这就是 Scala 语言中这些关键字之间的区别。

As myMethod has no parameters and is not affected by side-effects, it should be changed to val or as you say lazy val so it is only ran when needed.由于myMethod没有参数且不受副作用的影响,因此应将其更改为val或如您所说的lazy val以便仅在需要时运行。

It is more productive to program with intent rather than rely on compiler optimisation.有目的地编程比依赖编译器优化更有效率。

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

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