在“有效Scala”的Laziness部分,它说:
当val以lazy为前缀时,scala中的字段由需要计算。因为字段和方法在Scala中是等效的(以免字段是私有的[this])
“字段”和“方法”的含义是什么意思?这不是一个相当强烈的声明吗?
答案 0 :(得分:1)
嗯,这只是意味着您可以通过val
定义摘要def
,通过def
定义摘要val
。
例如
trait Server {
def port:Int
}
有一个抽象函数,即port
。您可以使用def
来实现(或定义或覆盖)此类
object DefaultServer extends Server {
override def port: Int = 80
}
但在这种情况下,每次访问port
都会导致函数应用程序(或方法调用),这是不必要的。出于这个简单的原因,Scala为我们提供了使用值实现抽象def
的可能性:
object DefaultServer extends Server {
override val port: Int = 80
}
这同样适用于抽象值。您可以使用相同的语法定义抽象值:
trait Server {
val port: Int
}
您可以使用def
:
object DefaultServer extends Server {
override def port: Int = 80
}
<强>稳定性强>
您可能想知道如果覆盖带有val
的摘要def
会发生什么情况,每次调用它时会给您一个不同的值。您是否会获得第一个计算值,因为该项目是val
,或者每次调用它时都会得到不同的值,因为实际的实现是def
。
例如:
object DefaultServer extends Server {
override def port: Int = scala.util.Random.nextInt()
}
幸运的是,Scala编译器会检测到此错误并抛出以下错误:
error: overriding value a in trait Server of type Int;
method a needs to be a stable, immutable value
override def port:Int = scala.util.Random.nextInt()
<强>懒惰强>
当涉及到懒惰时,这种统一的行为(以相同的方式处理领域和方法)非常有用。
首先请注意,lazy
抽象值不存在,即您无法将抽象val
定义为lazy
。
另一方面,由def
实现抽象lazy val
是完全合法且有用的。 lazy
值仅在第一次调用时计算并记忆(缓存并用于将来的调用)。
答案 1 :(得分:1)
模块提供的所有服务都应该通过统一的符号提供,不会背叛它们是通过存储还是通过计算来实现
在Scala中查看有关how it's implemented的更多信息。
P.S。 Scala中的UAP似乎是not completely implemented
答案 2 :(得分:0)
主要原因可能是lazy val
和def
在使用之前计算(而不是在首次定义时)。
差异在于lazy val
试图避免重新评估不变的值,这增加了将计算值保留在内存中的成本。