Scala 懒惰的人做什么?

Scala 懒惰的人做什么?,scala,lazy-evaluation,Scala,Lazy Evaluation,我注意到Scala提供了惰性VAL。但我不明白他们在做什么 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 scala>valx=15 x:Int=15 scala>延迟值y=13 y:Int= scala>x res0:Int=15 scala>y res1:Int=

我注意到Scala提供了
惰性VAL
。但我不明白他们在做什么

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
scala>valx=15
x:Int=15
scala>延迟值y=13
y:Int=
scala>x
res0:Int=15
scala>y
res1:Int=13

显示
y
是一个
lazy val
,但它与正常的
val
有何不同?

它们之间的区别是,定义时执行
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
这里,当值
x
y
从未使用时,只会
x
不必要地浪费资源。如果我们假设
y
没有副作用,并且我们不知道它被访问的频率(从来没有,一次,数千次),那么将它声明为
def
是没有用的,因为我们不想多次执行它


如果您想知道如何实现
惰性val
,请参见此。

它们之间的区别是,定义时执行
val
,而第一次访问时执行
惰性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
这里,当值
x
y
从未使用时,只会
x
不必要地浪费资源。如果我们假设
y
没有副作用,并且我们不知道它被访问的频率(从来没有,一次,数千次),那么将它声明为
def
是没有用的,因为我们不想多次执行它


如果您想知道如何实现
惰性VAL
,请参见此。

此功能不仅有助于延迟昂贵的计算,而且对于构造相互依赖或循环结构也很有用。例如,这会导致堆栈溢出:

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
但是对于懒惰的VAL,它工作得很好

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()

此功能不仅有助于延迟昂贵的计算,而且有助于构造相互依赖或循环结构。例如,这会导致堆栈溢出:

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
但是对于懒惰的VAL,它工作得很好

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
现在将抛出空指针异常,因为
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 

这被称为“早期初始值设定项”。有关更多详细信息,请参阅

还有
lazy
在没有循环依赖关系的情况下很有用,如下代码所示:

abstract class X {
  val x: String
  println ("x is "+x.length)
}

object Y extends X { val x = "Hello" }
Y
访问
Y
现在将抛出空指针异常,因为
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最容易理解为“(无arg)def”

与def一样,延迟val在被调用之前不会被计算。但结果会被保存,以便后续调用返回保存的值。记忆结果会占用数据结构中的空间,就像val一样

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

事实上,惰性VAL或多或少是作为已记忆的DEF实现的。您可以在此处阅读有关其实施的详细信息:


惰性val最容易理解为“(无arg)def”

与def一样,延迟val在被调用之前不会被计算。但结果会被保存,以便后续调用返回保存的值。记忆结果会占用数据结构中的空间,就像val一样

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

事实上,惰性VAL或多或少是作为已记忆的DEF实现的。您可以在此处阅读有关其实施的详细信息:


我知道答案已经给出,但我写了一个简单的例子,让像我这样的初学者更容易理解:

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”的值也将被考虑在内,而不是旧的值


希望这能有所帮助。

我知道答案已经给出,但我写了一个简单的例子,以便于像我这样的初学者理解:

var x = { println("x"); 15 }
lazy val y = { println("y"); x + 1 }
println("-----")
x = 17
println("y is: " + y)
scala> lazy val lazyEight = {
     |   println("I am lazy !")
     |   8
     | }
lazyEight: Int = <lazy>

scala> lazyEight
I am lazy !
res1: Int = 8
上述代码的输出为:

x
-----
y
y is: 18
可以看出,x在初始化时打印,但y在以相同方式初始化时不打印(我在这里故意将x作为var,以解释y何时初始化)。接下来,当调用y时,它将被初始化,最后一个“x”的值也将被考虑在内,而不是旧的值

希望这有帮助。

scala>lazy val lazyweight={
scala> lazy val lazyEight = {
     |   println("I am lazy !")
     |   8
     | }
lazyEight: Int = <lazy>

scala> lazyEight
I am lazy !
res1: Int = 8
|println(“我很懒!”) | 8 | } 懒散的人:Int= 斯卡拉>懒汉 我很懒! res1:Int=8
  • 所有VAL都在对象构造期间初始化
  • 使用lazy关键字将初始化延迟到第一次使用
  • 注意:延迟VAL不是最终版本,因此可能会显示性能缺陷
scala>lazy val lazyweight={
|println(“我很懒!”)
|   8
| }
懒散的人:Int=
斯卡拉>懒汉
我很懒!
res1:Int=8
  • 所有VAL都在对象构造期间初始化
  • 使用lazy关键字将初始化延迟到第一次使用
  • 注意:延迟VAL不是最终版本,因此可能会显示性能缺陷

惰性的演示-如上所述-定义时的执行与访问时的执行:(使用2.12.7 scala shell)

//编译器说这是