3

由于 Scala 中的继承线性化,我想了解我为案例类指定的特征是如何相对于 Scala 编译器自动生成和添加的两个特征进行排序的;即Product with Serializable(令人失望的是,它不是ProductN[...]从 2.12 开始的)。

我已经非常彻底地搜索了,我还没有找到它直接解决的问题。鉴于以下情况:

case class Cc(a: Int, b: Int) extends MyTraitA with MyTraitB

在 Scala 编译器自动生成代码之后,关于生成的继承顺序,以下哪一项是正确的假设?

  1. case class Cc(a: Int, b: Int) extends MyTraitA with MyTraitB with Product with Serializable
  2. case class Cc(a: Int, b: Int) extends Product with Serializable with MyTraitA with MyTraitB

然后,我还有一个问题。Product2[...]如果我明确地扩展到案例类,会发生什么不良或意外的影响?以下是插入重复的上述两段代码Product2[...]

  1. case class Cc(a: Int, b: Int) extends MyTraitA with MyTraitB with Product2[Int, Int] with Product with Serializable
  2. case class Cc(a: Int, b: Int) extends Product with Serializable with MyTraitA with MyTraitB with Product2[Int, Int]

IOW,是否存在任何不良的相互作用,因为两者ProductProduct2一起出现?

4

1 回答 1

3

感谢深入阅读 Bogdan Vakulenko 评论中提供的链接,第一个问题的明确答案是第 2 项:

case class Cc(a: Int, b: Int) extends Product with Serializable with MyTraitA with MyTraitB

再次感谢 Bogdan Vakulenko,第二个问题的答案是,在添加Product2[Int, Int]特征时不会发生任何不希望的事情,因为它扩展了Product特征。


有一个非常有趣的奖励答案。如果希望将编译器生成的接口推到特征继承顺序的后面,则需要显式定义编译器生成的接口。有几种方法可以做到这一点。

第一个也是最简单的方法是更改​​像这样出现的原始代码(不引用Product也不Serializable让编译器自动生成它们):

case class Cc(a: Int, b: Int) extends MyTraitA with MyTraitB

看起来像这样(明确定义ProductSerializable在特征列表的尾部):

case class Cc(a: Int, b: Int) extends MyTraitA with MyTraitB with Product with Serializable

第二个选项是添加Product with Serializable到两者/其中一个MyTraitA和/或MyTraitB这样:

trait MyTraitA extends Product with Serializable
trait MyTraitB extends Product with Serializable
case class Cc(a: Int, b: Int) extends MyTraitA with MyTraitB

这种技术也导致了理想的性状排序。

case class Cc(a: Int, b: Int) extends MyTraitA with MyTraitB with Product with Serializable

最后,集成Product2[Int, Int]就像明确定义所有内容一样简单,知道任何重叠都将通过 Scala 编译器中默认提供的出色的多重继承解析策略自动解决:

case class Cc(a: Int, b: Int) extends MyTraitA with MyTraitB with Product2[Int, Int] with Product with Serializable {
  override def _1: Int = a
  override def _2: Int = b
}
于 2019-05-27T21:08:16.830 回答