Scala线性化规则实战
限制在关注线性化之前,让我们指出Scala强加的多重继承限制。Scala多重继承限制Scala中的多重继承是使用特征实现的,它遵循线性化规则。
在继承层次结构中,如果存在显式扩展类的特征,则混合在此特征中的类也必须是特征父类的子类。 这意味着当混合扩展类的特征时,它们必须都具有相同的父级。
无法混合使用相同签名或不同返回类型定义或声明方法的特征。
当多个traits定义具有相同签名和返回类型的方法时,必须特别小心。 在声明方法并且预期实现方法的情况下,这不是问题,只有一个实现就足够了。
请记住,mixin traits的语法如下:class A使用C和D扩展B.此过程的规则如下:
1.从第一个扩展类或特征开始,然后写下完整的层次结构。我们将此称为线性化层次结构。
2.获取下一个特征并向下编写此层次结构 现在从该层次结构中删除已经在线性化层次结构中的所有类/特征将剩余特征添加到线性化层次结构的底部以创建新的线性化层次结构重复每个特征的第2步。
3.将类本身作为扩展线性化层次结构的最后一种类型示例让我们说上面的图表编码如下:
线性化正如我们已经看到的,特征提供了一种多重继承的形式。 在这种情况下,层次结构不一定是线性的,而是形成一个非循环图,需要在编译时展平。 线性化的作用是 - 它为一个类的所有祖先指定单个线性顺序,包括常规超类链和所有特征的父链。
我们不必处理不包含代码的特征的线性化。 但是,如果我们使用mixins,我们将不得不考虑它。
线性化将影响以下内容:方法定义变量(mutable-var和immutable-val),然而,如果线性化规则不明确,事情会变得更加复杂和出乎意料。
继承层次结构的规则在研究线性化规则之前,我们需要清楚Scala中的一些继承规则:在Java中,即使一个类没有显式扩展另一个类,它的超类也将是java.lang.Object。 Scala也是如此,等效基数是AnyRef。
直接扩展特征和扩展特质超类并使用with关键字混合特征之间存在相似性。
在较旧的Scala版本中,还有另一种名为ScalaObject的类型,它隐式添加到所有特征和类中。
使用这些规则,我们总是可以获得所有特征和类的规范形式,其中使用extends指定基类,然后使用with关键字添加所有特征。
线性化规则Scala中的线性化规则已定义并存在,以确保定义良好的行为。规则陈述如下:任何类的线性化必须包括它扩展的任何类(但不是trait)的未修改的线性化。
任何类的线性化必须包括其扩展的任何特征的线性化中的所有类和mixin特征,但mixin特征不一定以与它们混合的特征的线性化中出现的顺序相同的顺序出现。
线性化中的每个类或特征只能出现一次。
重复项被忽略。
我们已经在前面的一些例子中看到,不可能混合具有不同基类的特征,或者在基类不同时将特征混合到一个类中。
class A{
def m(s:String) = println(s"A($s)")
}
trait B extends A{
override def m(s:String) = super.m(s"B($s)")
}
trait C extends A{
override def m(s:String) = super.m(s"C($s)")
}
trait D extends A{
override def m(s:String) = super.m(s"D($s)")
}
trait E extends C{
override def m(s:String) = super.m(s"E($s)")
}
trait F extends C{
override def m(s:String) = super.m(s"F($s)")
}
class G extends D with E with F with B{
override def m(s:String) = super.m(s"G($s)")
}
object Test2 {
def main(args: Array[String]): Unit = {
val x = new G().m("")
}
}
Test2.main(Array())
如果没有线性化过程,就不清楚解析的位置。由于线性化过程,让我们通过应用上面提到的规则来写下来:
1. 从左往右 第一个特征(D) D->A->AnyRef->Any
2.第2个特征(E)
E->C->A->AnyRef->Any
从该层次结构中删除已经在线性化层次结构中的所有类/特征,这将删除A->AnyRef->Any,剩下E-C
将剩余的特征添加到线性化层次结构的底部以创建新的线性化层次结构
E->C->D->A->AnyRef->Any
3.第3个特征F
F->C->A->AnyRef->Any
从该层次结构中删除已经在线性化层次结构中的所有类/特征,这将删除A->AnyRef->Any,剩下F-C
F->C->E->C->D->A->AnyRef->Any
4.第4个特征B
B->A->AnyRef->Any
从该层次结构中删除已经在线性化层次结构中的所有类/特征,这将删除A->AnyRef->Any,剩下B
B->F->C->E->C->D->A->AnyRef->Any
5.将类本身作为扩展线性化层次结构的最后一种类型
G->B->F->E->C->D->A->AnyRef->Any
最终线性化结果就是G-> B->F->E->C->D->A->AnyRef->Any
也就是说 val x = new G().m("") 执行过程:
<==>super.m(s"G($s)")
<==>...B.m("G()")
<==>...F(B(G()))
<==>...E(F(B(G())))
<==>..C(E(F(B(G()))))
<==>...D(C(E(F(B(G())))))
<==>A(D(C(E(F(B(G()))))))
<==> println("A(D(C(E(F(B(G()))))))")
==A(D(C(E(F(B(G()))))))
所以上面打印结果就是: A(D(C(E(F(B(G()))))))