Scala:抽象案例类的toString函数

sul*_*man 1 inheritance scala typeclass case-class shapeless

假设我有一个case类定义如下:

case class User(name: String, age: Int)
Run Code Online (Sandbox Code Playgroud)

我想像这样重写它的toString方法:

 case class User(name: String, age: Int) {
    override def toString: String = 
      s"name = $name
        age = $age"
Run Code Online (Sandbox Code Playgroud)

这样,如果我跑步print(user.toString),我会得到:

name = nameOfUser
age = ageOfUser
Run Code Online (Sandbox Code Playgroud)

现在我有另一个类Computer,它被定义为

case class Computer(make: String, RAM: int, clockSpeed: Double)
Run Code Online (Sandbox Code Playgroud)

我想为所有值打印相同的内容。我想要类似的东西:

  make = makeOfComputer
  RAM = RAMOfComputer
  clockSpeed = speedOfComputer
Run Code Online (Sandbox Code Playgroud)

与其将上面的toString函数复制,粘贴和调整到Computer该类中,不如将其抽象化,以便任何case类都可以使用它。

我有一些想法可以使用

 CaseClassType.unapply(caseClassInstance).get.productIterator.toList
Run Code Online (Sandbox Code Playgroud)

获取案例类的值,并

 classOf[CaseClass].getDeclaredFields.map(_.getName)
Run Code Online (Sandbox Code Playgroud)

获取字段名称。这意味着我可以在不知道案例类的实际结构的情况下,找到案例类中所有值的列表以及所有字段名称的列表。

一旦有了这两个集合,就可以递归地遍历它们来创建字符串。我在想像下面这样的东西可以工作,但是不幸的是,scala不允许案例类继承自其他案例类。

case class StringifiableCaseClass(){
  override def toString: String =
     //get the values and the fieldnames and create a string
Run Code Online (Sandbox Code Playgroud)

我要做的就是扩展case类StringifiableCaseClass,它们将能够创建正确的字符串。

我想使用案例类作为基本类型的原因是我可以使用

 classOf[this.type]...etc
Run Code Online (Sandbox Code Playgroud)

  this.type.unapply(this)...etc
Run Code Online (Sandbox Code Playgroud)

在中StringifiableCaseClass

关于如何实现给定的目标,我有什么想法无法将案例类扩展到其他案例类?

Dim*_*ima 5

The base implementation does not have to be a case class. Just make it a trait, and then your case classes can all extend it.

 trait Stringification { self: Product => 
    override def toString() = 
      getClass.getDeclaredFields
      .zip(productIterator.toSeq)
      .map { case (a, b) => s"${a.getName}=$b" }
      .mkString("\n")
 }
Run Code Online (Sandbox Code Playgroud)

and then

  case class Foo(foo: String, bar: Int) extends Stringification
  case class Bar(foo: Foo, bar: String) extends Stringification
Run Code Online (Sandbox Code Playgroud)

... etc.