Совпадение типов по общей характеристике Scala

Я просто окунаю пальцы ног в дженерики, и мне интересно, есть ли лучший способ добиться следующего:

У меня есть запечатанная черта с абстрактным именем и переопределенным equals(). Я хочу, чтобы переопределенные равны совпадали как по типу, так и по имени. Ниже приводится то, что у меня есть.

sealed trait NamedCampaign[A <: NamedCampaign] {
 def name: String

 override def equals(obj: Any): Boolean = obj match {
 case x: A => x.name == this.name
 case _ => false
 }
}

case class AdCampaign(name: String, objective: String, status: String, buyingType: String) extends NamedCampaign[AdCampaign]
case class AdSet(name: String, status: String, dailyBudget: Int, lifetimeBudget: Int, startTime: Int, endTime: Int, campaign: String) extends NamedCampaign[AdSet]

В непрофессиональных условиях я хочу, чтобы два объекта считались равными, если они являются одним и тем же классом и имеют одно и то же имя. Есть ли лучший/более быстрый/более идиоматический способ сделать это?

1 ответ

То, что у вас есть, не может работать из-за стирания. Тип A не известен во время выполнения.

Адаптировано из этого связанного ответа:

sealed trait NamedCampaign[A <: NamedCampaign] {
 implicit def classTagA: ClassTag[A]
 def name: String
 override def equals(obj: Any): Boolean = obj match {
 case classTagA(x) => x.name == this.name
 case _ => false
 }
}

case class AdCampaign(name: String, objective: String, status: String,
 buyingType: String)(implicit val classTagA: ClassTag[AdCampaign])
 extends NamedCampaign[AdCampaign]

case class AdSet(name: String, status: String, dailyBudget: Int,
 lifetimeBudget: Int, startTime: Int, endTime: Int, campaign: String)
 (implicit val classTagA: ClassTag[AdSet]) extends NamedCampaign[AdSet]

Лучший способ написать это с помощью метода canEqual.

sealed trait NamedCampaign {
 def name: String
 def canEqual(that: Any): Boolean
 override def equals(other: Any): Boolean = other match {
 case that: NamedCampaign => (that canEqual this) &&
 (this.name == that.name)
 case _ => false
 }
}

case class AdCampaign(name: String, objective: String, status: String,
 buyingType: String) extends NamedCampaign {
 override def canEqual(that: Any) = that.isInstanceOf[AdCampaign]
}

case class AdSet(name: String, status: String, dailyBudget: Int,
 lifetimeBudget: Int, startTime: Int, endTime: Int, campaign: String)
 extends NamedCampaign {
 override def canEqual(that: Any) = that.isInstanceOf[AdSet]
}

Мои два цента: я не думаю, что когда-либо уместно переопределить equals по классу case. Вы пожалеете об этом в тот момент, когда захотите сравнить все поля (которые вы, вероятно, захотите сделать, скажем, unit тест).

licensed under cc by-sa 3.0 with attribution.