Scala:如何定义一个返回子类实例的方法

在我正在从事的项目中,有一些代码基本上如下:

sealed trait Character {
  def tags: Seq[String]
  def life: Int
  // other defs
}
object Character {
  def addTag[T <: Character](character: T,tag: String): T = {
    val newTags = character.tags :+ tag
//    character.copy(tags = newTags)  // this doesn't compile

    character match {
      case c: Person => c.copy(tags = newTags).asInstanceOf[T]
      case c: Beast => c.copy(tags = newTags).asInstanceOf[T]
      // ten more cases to match each subclass
      ......
      case _ => character
    }
  }
}

case class Person(title: String,firstName: String,lastName: String,tags: Seq[String],life: Int,weapon: String
                 ) extends Character
case class Beast(name: String,weight: Int
                ) extends Character
// ten other case classes that extends Character
......

代码可以工作,但是addTag方法看起来并不漂亮,原因有两个:首先,它使用asInstanceOf;其次,它有许多case c: ......行,每行几乎都是相同的。

有没有办法使代码更好?

st86591985 回答:Scala:如何定义一个返回子类实例的方法

由于copy方法特定于每个案例类(采用不同的参数),因此无法在超类中使用它。您可以做的是:


  sealed trait Character {
    def tags: Seq[String]

    def life: Int

    // other defs
  }

  trait Taggable[T <: Character] {
    def addTags(t: T,newTags: Seq[String]): T
  }

  object Character {
    def addTag[T <: Character: Taggable](character: T,tag: String): T = {
      val newTags = character.tags :+ tag
      implicitly[Taggable[T]].addTags(character,newTags)
    }
  }

  case class Person(title: String,firstName: String,lastName: String,tags: Seq[String],life: Int,weapon: String
                   ) extends Character

  object Person {
    implicit val taggable: Taggable[Person] = new Taggable[Person] {
      override def addTags(t: Person,newTags: Seq[String]): Person = t.copy(tags = newTags)
    }
  }

  case class Beast(name: String,weight: Int
                  ) extends Character

  Character.addTag(Person("","",Seq(),1,""),"")
//  Character.addTag(Beast("",1) // needs implicit as well

这使用必须由每个子类实现的Taggable类型类。

本文链接:https://www.f2er.com/3167337.html

大家都在问