对于 `case class Cc(a: Int, b: Int) extends MyTraitA`,带有 `Product` 和 `Serializable` 特征的 `MyTraitA` 出现在哪里?

For `case class Cc(a: Int, b: Int) extends MyTraitA`, where does `MyTraitA` appear with `Product` and `Serializable` traits?

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

我已经彻底搜索过了,但没有找到直接解决的问题。鉴于以下内容:

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[...] 显式扩展到案例 class,会发生什么不良或意外的结果?以下是上面插入的 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 一起出现,是否存在任何不良交互?

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

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

再次感谢 Bogdan Vakulenko,第二个问题的答案是添加 Product2[Int, Int] 特征时不会出现任何不良情况,因为它扩展了 Product 特征。


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

第一个也是最简单的方法是更改​​如下所示的原始代码(不引用 ProductSerializable 并让编译器自动生成它们):

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 and/or MyTraitB 的 both/either 中:

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
}