快速提示: 本例子出自 Scala for Java Refugees Part 5: Traits and Types 教程。
假设我有下列特质:Student,Worker,Underpaid和Young。
如何声明一个类(不是实例),名为CollegeStudent,并拥有所有这些特质?
注意: 我知道简单的情况,例如只有一两个Trait的CollegeStudent:
class CollegeStudent extends Student with Worker
快速提示: 本例子出自 Scala for Java Refugees Part 5: Traits and Types 教程。
假设我有下列特质:Student,Worker,Underpaid和Young。
如何声明一个类(不是实例),名为CollegeStudent,并拥有所有这些特质?
注意: 我知道简单的情况,例如只有一两个Trait的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编译器通过创建“每个特质的副本以形成类和特质的高大、单列层次结构”,这个过程称为线性化来解决这个问题。
在这种情况下,具有相同字段名的多个特质的扩展将无法编译,这与“如果您扩展了一个类并提供了自己的版本的方法,但未添加override关键字”完全相同。
由于它确定了继承树的形状,因此线性化顺序确实是一个非常重要的问题。例如,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
这完美地体现了线性化继承图的结构。