我正在浏览 effective scala slides它在幻灯片 10 中提到,切勿在抽象成员的 trait
中使用 val
,而应使用 def
。该幻灯片没有详细提及为什么在 trait
中使用抽象 val
是一种反模式。如果有人可以解释在抽象方法的特征中使用 val 与 def 的最佳实践,我将不胜感激
最佳答案
def
可以通过 def
、val
、lazy val
或对象
。所以它是定义成员的最抽象的形式。由于特征通常是抽象接口(interface),所以说你想要一个val
就是说如何实现应该做什么。如果您请求 val
,则实现类不能使用 def
。
仅当您需要稳定的标识符时才需要 val
,例如对于路径依赖类型。这是您通常不需要的东西。
比较:
trait Foo { def bar: Int }
object F1 extends Foo { def bar = util.Random.nextInt(33) } // ok
class F2(val bar: Int) extends Foo // ok
object F3 extends Foo {
lazy val bar = { // ok
Thread.sleep(5000) // really heavy number crunching
42
}
}
如果你有
trait Foo { val bar: Int }
您将无法定义 F1
或 F3
。
好吧,让您感到困惑并回答@om-nom-nom - 使用抽象val
可能会导致初始化问题:
trait Foo {
val bar: Int
val schoko = bar + bar
}
object Fail extends Foo {
val bar = 33
}
Fail.schoko // zero!!
这是一个丑陋的问题,我个人认为应该通过在编译器中修复它来在未来的 Scala 版本中消失,但是,是的,目前这也是不应该使用抽象 val
的一个原因s。
编辑(2016 年 1 月):您可以使用 lazy val
实现覆盖抽象 val
声明,这样也可以防止初始化失败。
关于scala - 何时在 Scala 特征中使用 val 或 def?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/19642053/