这是一个引起头痛的特质线性益智游戏。我基本上输入Node
,定义equals
和hashCode
与其他Node
进行比较。我有Selector
类型可以包含Node
以及额外数据,因此有自己的equals
和hashCode
与其他Selector
进行比较第
现在我有一个Standalone
类型,它结合了Node
和Selector
,但我对equals
和hashCode
的线性化不一致(?):
trait Selector { override def hashCode = 1 }
trait Event extends Selector
trait Node { override def hashCode = 2 }
trait Standalone extends Node with Event
当我从Event
或Standalone
延伸时,现在一切正常(调用更具体的hashCode 1):
object Single1 extends Event
Single1.hashCode // 1 -- ok
object Single2 extends Standalone
Single2.hashCode // 1 -- ok
如果我从这两个顺序延伸,那也没关系:
object Compound1 extends Standalone with Event
Compound1.hashCode // 1 -- Ok
但是当我这样做时它会变得混乱:
object Compound2 extends Event with Standalone
Compound2.hashCode // 2 -- no!!!!!!!!
我做了一点.dot图表(mixins从左到右排序):
因此,如果我正确理解linearisation rules,我应该始终使用hashCode
实施的Selector
。对这种行为的唯一解释是,存在某种贪婪/深度优先的事情......?
此外,如果有一种技术我可以用来确保在Standalone
混入时,确保Selector
否决Node
(除了复制equals
从hashCode
到Selector
)和Standalone
,我将非常感激。
这是Scala 2.9.2。
答案 0 :(得分:4)
最好去Spec这类事情。
该算法在5.1.2 Class Linearization
解释它,C类的线性化是C,然后是从最右边的项开始扩展的东西的线性化。然后是在线性化中删除重复项的最后一步,只保留最右边的重复项。
所以在Compound1
的示例中(忽略像AnyRef这样的内置函数):
L(Compound1) = Compound1 + L(Event) + L(Standalone)
L(Event) = Event + L(Selector)
L(Selector) = Selector
L(Standalone) = Standalone + L(Event) + L(Node)
L(Node) = Node
把它放在一起:
L(Compound1) = Compound1 Event Selector Standalone Event Selector Node
删除重复项:
Compound1 Standalone Event Selector Node
对于Compound2
,它最终成为:
Compound2 Standalone Node Event Selector
至于另一个问题,我认为最简单的方法是覆盖Standalone
中的方法并在超类中调用所需的方法。
trait Standalone extends Node with Event { override def hashCode = super[Event].hashCode }
假设这不是“复制”的意思。