快速说明:教程Scala for Java Refugees Part 5: Traits and Types中的示例。
假设我具有 Student、Worker、Underpaid 和 Young 的特征。
我如何声明一个具有所有这些特征的类(而不是实例)CollegeStudent?
注意:我知道最简单的情况,例如具有一两个特征的 CollegeStudent:
class CollegeStudent extends Student with Worker
快速说明:教程Scala for Java Refugees Part 5: Traits and Types中的示例。
假设我具有 Student、Worker、Underpaid 和 Young 的特征。
我如何声明一个具有所有这些特征的类(而不是实例)CollegeStudent?
注意:我知道最简单的情况,例如具有一两个特征的 CollegeStudent:
class CollegeStudent extends Student with Worker
这很简单,在声明一个类时,您只需尽可能多地使用“with”关键字
class CollegeStudent extends Student with Worker with Underpaid with Young
如果一个特性改变了类的行为,特性的顺序可能很重要,这完全取决于你使用的特性。
此外,如果您不想拥有一个始终使用相同特征的类,您可以稍后使用它们:
class CollegeStudent extends Student
new CollegeStudent with Worker with Underpaid with NotSoYoungAnymore
我认为不仅要解释语法,还要解释特征的排序所起的作用是非常重要的。我发现 Jason Swartz 的Learning Scala(第 177 页)中的解释非常有启发性。
一个 Scala 类可以同时扩展多个特征,但 JVM 类只能扩展一个父类。Scala 编译器通过创建“每个特征的副本以形成类和特征的高单列层次结构”来解决这个问题,这个过程称为线性化。
在这种情况下,扩展具有相同字段名称的多个特征将无法编译,就像您正在扩展一个类并提供自己的方法版本但未能添加覆盖关键字一样“。
而且由于它决定了继承树的形状,线性化顺序确实是一个非常重要的问题。例如,class D extends A with B with C
(其中 A 是一个类,B 和 C 是特征)将变为class D extends C extends B extends A
. 以下几行同样来自书中,完美地说明了这一点:
trait Base { override def toString = "Base" }
class A extends Base { override def toString = "A->" + super.toString }
trait B extends Base { override def toString = "B->" + super.toString }
trait C extends Base { override def toString = "C->" + super.toString }
class D extends A with B with C { override def toString = "D->" + super.toString }
调用new D()
将使 REPL 打印以下内容:
D->C->B->A->Base
完美体现了线性化继承图的结构。