由于 Scala中的继承线性化,我想了解我为案例类指定的特征是如何相对于 Scala 编译器自动生成和添加的两个特征进行排序的;即Product with Serializable
(令人失望的是,它不是从 2.12 开始ProductN[...]
)。
我已经非常彻底地搜索了,但我没有找到直接解决的问题。鉴于以下情况:
case class Cc(a: Int, b: Int) extends MyTraitA with MyTraitB
在 Scala 编译器自动生成代码之后,以下哪项是关于结果继承排序的正确假设?
case class Cc(a: Int, b: Int) extends MyTraitA with MyTraitB with Product with Serializable
case class Cc(a: Int, b: Int) extends Product with Serializable with MyTraitA with MyTraitB
然后,我还有一个问题。如果我显式地将Product2[...]
扩展到案例类,可能会产生哪些不良或意外的影响?以下是上面两段重复插入Product2[...]
的代码:
case class Cc(a: Int, b: Int) extends MyTraitA with MyTraitB with Product2[Int, Int] with Product with Serializable
case class Cc(a: Int, b: Int) extends Product with Serializable with MyTraitA with MyTraitB with Product2[Int, Int]
IOW,是否存在任何不良的相互作用,因为Product
和Product2
一起出现?
由于深入阅读了Bogdan Vakulenko评论中提供的链接,第一个问题的明确答案是第2项:
case class Cc(a: Int, b: Int) extends Product with Serializable with MyTraitA with MyTraitB
再次感谢波格丹·瓦库连科,第二个问题的答案是,在添加Product2[Int, Int]
性状时,鉴于它扩展了Product
性状,因此不应发生任何不良情况。
有一个非常有趣的奖励答案。如果需要将编译器生成的接口推送到特征继承排序的后面,则需要显式定义编译器生成的接口。有几种方法可以做到这一点。
第一个也是最简单的是更改如下所示的原始代码(没有引用Product
也没有Serializable
,并让编译器自动生成它们):
case class Cc(a: Int, b: Int) extends MyTraitA with MyTraitB
如下所示(明确定义Product
并在特征列表的末尾Serializable
):
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
}