懒惰的val做什么?

我注意到Scala提供了lazy vals 。 但我不明白他们做什么。

 scala> val x = 15 x: Int = 15 scala> lazy val y = 13 y: Int = <lazy> scala> x res0: Int = 15 scala> y res1: Int = 13 

REPL表明y是一个lazy val ,但它与正常的val不同呢?

它们之间的区别在于,在定义时执行lazy val而在第一次访问时执行lazy val

 scala> val x = { println("x"); 15 } x x: Int = 15 scala> lazy val y = { println("y"); 13 } y: Int = <lazy> scala> x res2: Int = 15 scala> y y res3: Int = 13 scala> y res4: Int = 13 

与一个方法(用def定义)相比,一个lazy val被执行一次,然后再也不会执行。 当操作需要很长时间才能完成,以及何时不确定是否稍后使用时,这可能非常有用。

 scala> class X { val x = { Thread.sleep(2000); 15 } } defined class X scala> class Y { lazy val y = { Thread.sleep(2000); 13 } } defined class Y scala> new X res5: X = X@262505b7 // we have to wait two seconds to the result scala> new Y res6: Y = Y@1555bd22 // this appears immediately 

在这里,当xy值从不使用时,只有x不必要地浪费资源。 如果我们假设y没有任何副作用,并且我们不知道它被访问的频率(从来没有,一次,几千次),那么将它声明为def是没有用的,因为我们不想多次执行它。

如果你想知道如何实现lazy vals ,看到这个问题 。

这个特性不仅有助于延迟昂贵的计算,还有助于构造相互依赖或循环结构。 例如,这会导致堆栈溢出:

 trait Foo { val foo: Foo } case class Fee extends Foo { val foo = Faa() } case class Faa extends Foo { val foo = Fee() } println(Fee().foo) //StackOverflowException 

但与懒惰的vals,它工作正常

 trait Foo { val foo: Foo } case class Fee extends Foo { lazy val foo = Faa() } case class Faa extends Foo { lazy val foo = Fee() } println(Fee().foo) //Faa() 

另外lazy没有循环依赖是有用的,如下面的代码所示:

 abstract class X { val x: String println ("x is "+x.length) } object Y extends X { val x = "Hello" } Y 

现在访问Y将抛出空指针exception,因为x尚未初始化。 以下,但是,工作正常:

 abstract class X { val x: String println ("x is "+x.length) } object Y extends X { lazy val x = "Hello" } Y 

编辑:以下也将工作:

 object Y extends { val x = "Hello" } with X 

这被称为“早期初始化器”。 看到这个问题的更多细节。

懒惰的val最容易理解为“ memoized def”。

就像一个def,一个懒惰的val不会被调用,直到它被调用。 但是结果被保存,以便后续的调用返回保存的值。 记忆的结果在数据结构中占用空间,就像val。

正如其他人所提到的,一个懒惰的val的用例是延迟昂贵的计算,直到它们被需要并存储它们的结果,并且解决值之间的某些循环依赖关系。

事实上,懒惰的vals实际上是作为memoized defs来实现的。 你可以在这里阅读他们的实现细节:

http://docs.scala-lang.org/sips/pending/improved-lazy-val-initialization.html

我明白,答案是给出的,但我写了一个简单的例子,以便像我这样的初学者很容易理解:

 var x = { println("x"); 15 } lazy val y = { println("y"); x+1 } println("-----") x = 17 println("y is: " + y) 

以上代码的输出是:

 x ----- y y is: 18 

可以看出,x在初始化的时候被打印出来,但是当它以相同的方式被初始化的时候,y不会被打印出来(我在这里已经把x当成了var来解释什么时候y被初始化了)。 接下来,当y被调用时,它被初始化,以及最后'x'的值被考虑,但不是旧的。

希望这可以帮助。

 scala> lazy val lazyEight = { | println("I am lazy !") | 8 | } lazyEight: Int = <lazy> scala> lazyEight I am lazy ! res1: Int = 8 
  • 所有的vals在对象构造期间被初始化
  • 使用lazy关键字推迟初始化,直到第一次使用
  • 注意 :懒惰的vals不是最终的,因此可能会performance出性能上的缺陷