更符合Scala习惯的是什么:trait TraitA扩展TraitB还是trait TraitA { self: TraitB => }?

19

除了继承方面之外,下面这些类模板有什么区别:

1| trait TraitA extends TraitB

2| trait TraitA { self: TraitB => }

我希望将职责分配给 TraitATraitB,但前者没有后者无法正常运行。

您如何表达这个意图? 对我来说,解决方案[2]可能是比较自然的方法。但我不想让实现者混合需要混入的东西,从而增加负担。


可能重复的问题:Scala自类型和特征子类之间有什么区别? - om-nom-nom
1个回答

16

通常我更偏好使用[1],因为正如您所说,实现者不需要混合(子类型)TraitB。也许如果出于某种原因希望继承TraitB中的具体实现并迫使实现者在TraitB的子类型中进行选择,则更倾向于[2]。尽管如此,[1]同样具有灵活性。

我只在必要时使用[2],例如当类型不是已知类或特征时,

// Here, Matrix cannot extend type parameter Repr
trait Matrix[+Repr <: Matrix[Repr]] { self: Repr =>
  ...
}

更新。 这里还有一个小差别,

trait B
trait A { self: B => }
def g(ab: A): B = ab // Type mismatch: found A, required B

尽管类型已被合并,但无法将A 用作B这是一种可选的限制,有些让人烦恼。


2
谈到你的更新。我认为“小烦恼”非常有用,可以让人表达一个A“与之合作”,但同时“不是”一个B的关系。对我来说,这有点像私有继承和公共继承。 - Tim Friske
从历史上看,自类型注释的动机是第一个差异,至少在Odersky&Zenger的论文“可伸缩组件抽象”中是这样推动这个特性的(如果感兴趣,可以在Google Scholar上找到该论文)。 - Blaisorblade

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接