3

据我了解,Scala 线性化函数算法是右优先深度优先搜索,然后消除结果列表中每个特征的最后一次出现。

这个算法有两个方面对我来说似乎相当随意:

  • 为什么首先探索特征而不是类别而不是相反?
  • 为什么从右到左而不是从左到右遍历特征?

这些任意的约定和其他约定一样好吗?或者这些设计决策背后有什么理由?

请注意,我的问题仅涉及算法的“水平”排序。

4

1 回答 1

9

这些武断的约定和其他约定一样好吗?

不,这些不是任意的。线性化是以这种方式完成的,因为它是为您提供理智的方法解析顺序 (MRO)的唯一方法。

为什么首先探索特征而不是类别而不是相反?

这仅适用于给定的类定义,因为它扩展的特征出现在它扩展的类之前。这是因为超类/特征是从右到左探索的——这将我们带到你的第二点。

为什么从右到左而不是从左到右遍历特征?

这是一个非常简单的激励示例。

type MyType = T1 with T2
// Creating new instance using alias
new MyType with T3
// Creating new instance directly
new T1 with T2 with T3

我们希望上面示例中的两个实例具有相同的线性化。当使用类型别名时,我们在右侧“堆叠”附加特征,因此我们希望右侧的特征在 MRO 中具有最高优先级,因此在线性化中排在首位。

这是我想出的一个快速示例,用于说明特征和类的线性化:

class Base { override def toString = "Base" }
trait A { abstract override def toString = "A " + super.toString }
trait B { abstract override def toString = "B " + super.toString }
trait C { abstract override def toString = "C " + super.toString }
trait D { abstract override def toString = "D " + super.toString }
trait E { abstract override def toString = "E " + super.toString }
trait F { abstract override def toString = "F " + super.toString }
class X extends Base with A with B { override def toString = "X " + super.toString }
class Y extends X with C with D { override def toString = "Y " + super.toString }
class Z extends Y with E with F { override def toString = "Z " + super.toString }
new Z
// res0: Z = Z F E Y D C X B A Base

您可以从toString输出中看到这里的线性化是Z F E Y D C X B A Base,这正是我对给定层次结构所期望的。例如,由于ZextendsY混合了 trait C,我们期望Y的行为出现在 之前C,但之后Z以及它的混合EF

Scala 编程,第一版:特性的第 12 章的简单参考。(我认为这最近没有改变,所以第一版应该还是准确的。)

于 2013-11-06T09:17:10.823 回答