Для `case-класса Cc(a: Int, b: Int) расширяется MyTraitA`, где`MyTraitA` появляется с признаками `Product` и`Serializable`?
Из-за линеаризации наследования в Scala я хотел бы понять, как черты, которые я указываю для класса наблюдения, упорядочиваются относительно двух черт, автоматически генерируемых и добавляемых компилятором Scala; т.е. Product with Serializable
(и, к сожалению, это не ProductN[...]
по состоянию на 2.12).
Я довольно тщательно искал и не нашел прямого обращения. Учитывая следующее:
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
появляются вместе?
1 ответ
Благодаря глубокому прочтению ссылки, предоставленной в комментарии Богдана Вакуленко, явный ответ на первый вопрос - пункт 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
}