懒惰的 val
lazy val
是一种语言功能,其中 val
的初始化被延迟,直到第一次访问它为止。在那之后,它就像一个普通的 val
。
要使用它,请在 val
之前添加 lazy
关键字。例如,使用 REPL:
scala> lazy val foo = {
| println("Initializing")
| "my foo value"
| }
foo: String = <lazy>
scala> val bar = {
| println("Initializing bar")
| "my bar value"
| }
Initializing bar
bar: String = my bar value
scala> foo
Initializing
res3: String = my foo value
scala> bar
res4: String = my bar value
scala> foo
res5: String = my foo value
此示例演示了执行顺序。当声明 lazy val
时,保存到 foo
值的所有内容都是一个尚未评估的惰性函数调用。当设置常规 val
时,我们看到 println
调用 execute,并将值赋给 bar
。当我们第一次看到 println
执行时评估 foo
时 - 而不是第二次评估 println
时。同样,当评估 bar
时,我们看不到 println
执行 - 只有在声明时才会执行。
何时使用’懒惰'
-
初始化计算量很大,并且使用
val
很少见。lazy val tiresomeValue = {(1 to 1000000).filter(x => x % 113 == 0).sum} if (scala.util.Random.nextInt > 1000) { println(tiresomeValue) }
tiresomeValue
需要很长时间才能计算出来,而且并不总是使用它。使它成为一个节省 17 可以节省不必要的计算。 -
解决循环依赖关系
让我们看一个示例,其中有两个对象需要在实例化期间同时声明:
object comicBook { def main(args:Array[String]): Unit = { gotham.hero.talk() gotham.villain.talk() } } class Superhero(val name: String) { lazy val toLockUp = gotham.villain def talk(): Unit = { println(s"I won't let you win ${toLockUp.name}!") } } class Supervillain(val name: String) { lazy val toKill = gotham.hero def talk(): Unit = { println(s"Let me loosen up Gotham a little bit ${toKill.name}!") } } object gotham { val hero: Superhero = new Superhero("Batman") val villain: Supervillain = new Supervillain("Joker") }
如果没有关键字
lazy
,则各个对象不能是对象的成员。执行这样的程序将导致这样的程序。通过使用lazy
,可以在初始化之前分配引用,而不必担心具有未初始化的值。