7

我注意到有几个关于如何在抽象类和特征之间进行选择的讨论,但似乎没有一个集中在以下点上。让我使用抽象类的一个原因是,它们可以有构造函数参数,而特征不能。但为什么不是以下

trait X {
  def haha: Int
}
class Y(val haha: Int) extends X

甚至不需要早期定义来让一切正常工作(我担心)。抽象类版本是

abstract class X(haha: Int)
class Y(val haha: Int) extends X(haha)

而且我不喜欢抽象类版本,因为当您多次扩展时,这些构造函数参数无处不在(也许有人告诉我如何避免这种情况?)。

我知道抽象类可以更好地使用 Java 进行插值,并且更符合“is-a”概念。尽管如此,有什么理由我应该在某处使用抽象类吗?谢谢!

4

1 回答 1

9

类参数不必是成员(字段或定义)。

abstract class X(haha: Int) {
  val hoho = 2 * haha  // compile-time constant
}

同样,特征初始化顺序取决于线性化(混合顺序),这就是特征成员应该是 defs 而不是 vals 的原因。(而且你总是可以用 val 覆盖 def。)使用抽象类,你知道你的 super 是谁,并且你正在为子类定义扩展点。

但请注意,您的抽象类的 val 位置错误:

abstract class X(val haha: Int)
class Y(haha: Int) extends X(haha)

也就是说,您会期望 X 决定参数是否是 val (并且不一定是)。在 X 或 Y 中使用参数可以将其变成一个字段。

您对类的值参数的观察也适用于类型参数:将 Foo[A] 向上传递是多么令人讨厌。所以在 Scala 中,我们可以有一个成员类型 A 来代替它可以保持抽象,直到在叶子中定义。但这实际上与是否定义特征或类无关。

但是特征参数正在进入 Scala。(请参阅 Scala 错误以了解由于这个原因而属于低优先级的早期定义。)

于 2012-12-11T22:33:33.317 回答