【问题标题】:Scala: Abstracting the toString function of case classesScala:抽象案例类的 toString 函数
【发布时间】:2019-03-19 14:39:46
【问题描述】:

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

case class User(name: String, age: Int)

我想像这样覆盖它的toString 方法:

 case class User(name: String, age: Int) {
    override def toString: String = 
      s"name = $name
        age = $age"

所以如果我运行print(user.toString),我会得到:

name = nameOfUser
age = ageOfUser

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

case class Computer(make: String, RAM: int, clockSpeed: Double)

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

  make = makeOfComputer
  RAM = RAMOfComputer
  clockSpeed = speedOfComputer

与其将上面的toString 函数复制、粘贴和调整到Computer 类,我宁愿将其抽象出来,以便任何案例类都可以使用它。

我的一些想法是我可以使用的

 CaseClassType.unapply(caseClassInstance).get.productIterator.toList

获取案例类的值和

 classOf[CaseClass].getDeclaredFields.map(_.getName)

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

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

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

我所要做的就是让案例类扩展StringifiableCaseClass,然后他们就能创建正确的字符串。

之所以要使用case类作为基类型,是因为可以使用

 classOf[this.type]...etc

  this.type.unapply(this)...etc

StringifiableCaseClass

鉴于我无法使用其他案例类扩展案例类,我有什么想法可以实现我的目标吗?

【问题讨论】:

  • 你可以接受使用 Shapeless 之类的东西吗?

标签: scala inheritance typeclass shapeless case-class


【解决方案1】:

基本实现不必是案例类。只需让它成为一个特征,然后你的案例类都可以扩展它。

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

然后

  case class Foo(foo: String, bar: Int) extends Stringification
  case class Bar(foo: Foo, bar: String) extends Stringification

...等等

【讨论】:

    【解决方案2】:

    如果我正确理解您的用例,您可以使用 Cats 默认 Show 类型类,或者,如果您需要更多自定义行为,您可以直接使用带有 Shapeless 的泛型派生来实现您的目标。

    对于 Cat 的 Show 更简单的场景,请阅读 here

    正如您所读到的,它的语法可以让您在任何T 范围内具有Show[T]myObject.show 上执行myObject.show

    如果您想要更可定制的行为,可以尝试直接使用 Shapeless。您可以在 this example Show type-class 中找到您需要的示例,您可以看到它正在运行 here

    鉴于这些案例类:

      sealed trait Super
      case class Foo(i: Int, s: String) extends Super
      case class Bar(i: Int) extends Super
      case class BarRec(i: Int, rec: Super) extends Super
    
      sealed trait MutualA
      case class MutualA1(x: Int) extends MutualA
      case class MutualA2(b: MutualB) extends MutualA
    
      sealed trait MutualB
      case class MutualB1(x: Int) extends MutualB
      case class MutualB2(b: MutualA) extends MutualB
    

    它将打印:

    Bar(i = 0)   
    BarRec(i = 1, rec = Foo(i = 0, s = foo))   
    MutualA2(b = MutualB2(b = MutualA1(x = 0)))
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2017-04-04
      • 2018-10-22
      相关资源
      最近更新 更多