0

在“Effective Scala”的懒惰部分,它说:

当 val 以lazy 为前缀时,scala 中的字段由需要计算。因为字段和方法在 Scala 中是等价的(以免字段是私有的[this])

“字段”和“方法”等价是什么意思?这不是一个相当强烈的声明吗?

4

3 回答 3

1

好吧,它只是意味着您可以通过 a 定义一个抽象valdefdef通过a 定义一个抽象val

例如

trait Server {
  def port:Int
}

有一个抽象函数,即port。您可以肯定地用 a 实现(或定义或覆盖)它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用 a覆盖一个抽象会发生什么def,每次调用它都会给你一个不同的值。您会因为项目是 a 而获得第一个计算值,val还是因为实际实现是 a ,所以每次调用它时都会获得不同的值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抽象值不存在,即您不能将抽象定义vallazy.

另一方面,def通过 a实现抽象是完全合法且有用的。lazy vallazy值将仅在第一次调用时计算并记忆(缓存并用于将来的调用)。

于 2015-01-25T10:59:32.160 回答
1

由于统一访问原则,字段和方法是等效的:

一个模块提供的所有服务都应该通过一个统一的符号来获得,这并没有暴露它们是通过存储还是通过计算来实现的

查看更多关于它是如何在 Scala 中实现的信息。

Scala 中的 PS UAP 似乎没有完全实现

于 2015-01-25T13:44:03.777 回答
0

主要原因可能是,lazy val并且def在使用之前计算(而不是在首次定义时)。

不同之处在于lazy val试图避免重新评估不变的值,这增加了将计算值保存在内存中的成本。

于 2015-01-24T13:59:15.220 回答