scala - 何时在 Scala 特征中使用 val 或 def?

标签 scala inheritance traits

我正在浏览 effective scala slides它在幻灯片 10 中提到,切勿在抽象成员的 trait 中使用 val,而应使用 def。该幻灯片没有详细提及为什么在 trait 中使用抽象 val 是一种反模式。如果有人可以解释在抽象方法的特征中使用 val 与 def 的最佳实践,我将不胜感激

最佳答案

def 可以通过 defvallazy 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 }

您将无法定义 F1F3

<小时/>

好吧,让您感到困惑并回答@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/

相关文章:

generics - 使用泛型将 java 接口(interface)移植到 scala trait

amazon-web-services - Hadoop s3 配置文件丢失

scala - UDF 与自定义表达式

jpa - Kotlin数据类继承+拷贝方法

generics - 为什么我不能用 let _ : Arc<dyn Trait> = value. into() 创建一个 trait 对象?

带有引用的 Rust 泛型 AddAssign

java - 从 Spring RESTful 服务运行 Spark 作业

scala - 在 Scala 2.11+ 中如何准确地使用单例类型作为类型证据?

c# - 为什么访问静态成员 "through"继承类型有用?

c++ - 为什么 C++ 不使用父类构造函数?