我注意到有一些关于如何在抽象类和特征之间进行选择的讨论,但似乎没有一个人关注以下一点。让我使用抽象类的原因之一是,它们可以有构造函数参数,而特征则不能。但为什么不是下面的
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”概念。尽管如此,我是否有任何理由应该在某处使用抽象类?谢谢!
最佳答案
类参数不必是成员(字段或 def)。
abstract class X(haha: Int) {
val hoho = 2 * haha // compile-time constant
}
同样,特征初始化顺序取决于线性化(混合顺序),这就是特征成员应该是 def 而不是 val 的原因。 (并且您始终可以使用 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 错误以了解早期定义,因此这些定义的优先级较低。)
关于Scala:抽象类构造函数参数与 Trait val 成员?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/13828926/