4

这是一个让我头疼的特征线性化谜题。我基本上有类型Node,它定义equalshashCode与其他Nodes 进行比较。而且我有一个Selector类型,可以将 aNode与额外的数据一起包装,因此有自己的类型equalshashCode可以与其他Selectors 进行比较。

现在我有一个Standalone结合Nodeand的类型Selector,但是我得到不一致的(?)关于equalsand的线性化hashCode

trait Selector { override def hashCode = 1 }
trait Event extends Selector

trait Node { override def hashCode = 2 }
trait Standalone extends Node with Event

现在一切都很好(更具体的 hashCode 1 被称为)当我从Eventor扩展时Standalone

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!!!!!!!!

我做了一个小点图(mixin 从左到右排序):

在此处输入图像描述

所以,如果我正确理解线性化规则,我应该总是hashCodeSelector. 这种行为的唯一解释是涉及某种贪婪/深度优先的事情......?

此外,如果我可以使用一种技术来确保无论何时Standalone混入,都可以确保Selector否决Node(复制equalshashCodefrom SelectortoStandalone除外),这将非常感激。

这是 Scala 2.9.2。

4

1 回答 1

4

这种事情最好去规范。该算法描述于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 }  

假设这不是您所说的“复制”。

于 2012-06-23T22:17:37.097 回答