懶惰的 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
,可以在初始化之前分配引用,而不必擔心具有未初始化的值。