简体   繁体   中英

Type matching on generic Scala trait

I am just dipping my toes into generics and am wondering if there is a better way to achieve the following:

I have a sealed trait that has an abstract name and an overridden equals(). I want the overridden equals to match on both type and name. Below is what I have.

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]

In layman's terms, I want two objects to be considered equal if they are the same class and have the same name. Is there a better/faster/more idiomatic way of doing this?

What you have can't work because of erasure. The type A isn't known at runtime.

Adapted from this related answer :

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]

A better way to write this is with a canEqual method.

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]
}

My two cents: I don't think it's ever appropriate to override equals on a case class. You'll regret it the moment you ever want to compare all of the fields (which you're likely to want to do in, say, a unit test).

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM