Scala:抽象 case 类 的 toString 函数
Scala: Abstracting the toString function of case classes
假设我有一个案例class定义如下:
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
的 class,它被定义为
case class Computer(make: String, RAM: int, clockSpeed: Double)
我想为它的所有值打印相同的内容。我想要这样的东西:
make = makeOfComputer
RAM = RAMOfComputer
clockSpeed = speedOfComputer
与其将上述 toString
函数复制、粘贴和改编到 Computer
class,我宁愿将其抽象化,以便它可以在任何情况下使用 class.
我有一些想法可以使用
CaseClassType.unapply(caseClassInstance).get.productIterator.toList
获取案例class和
的值
classOf[CaseClass].getDeclaredFields.map(_.getName)
获取字段名称。这意味着我可以在完全不知道 case class 的实际结构的情况下找到 case class 中所有值的列表以及所有字段名称的列表。
一旦我有了这两个集合,我就可以递归地遍历它们来创建字符串。我在想像下面这样的东西可以工作但不幸的是scala不允许 case classes 从其他 case classes.
继承
case class StringifiableCaseClass(){
override def toString: String =
//get the values and the fieldnames and create a string
我所要做的就是让案例 classes 扩展 StringifiableCaseClass
,他们将能够创建正确的字符串。
之所以要用case class作为基本类型是因为我可以用
classOf[this.type]...etc
和
this.type.unapply(this)...etc
在 StringifiableCaseClass
中。
关于如何实现我想要的东西的任何想法我不能将案例 classes 扩展到其他案例 classes?
如果我正确理解了你的用例,你可以使用 Cats 默认 Show
type-class 或者,如果你需要更多自定义行为,你可以直接使用泛型推导 Shapeless
实现你所追求的。
有关 Cat Show
更简单的场景,请阅读 here。
如您所见,它的语法可让您对范围内具有 Show[T]
的任何 T
执行 myObject.show
。
如果您想要更可定制的行为,您可以尝试直接使用 Shapeless。在 this example Show
type-class and you can see it running here.
中可以找到您需要的示例
鉴于这些案例 classes:
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)))
基本实现不一定是案例class。让它成为一个特征,然后你的案例 classes 都可以扩展它。
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
...等等
假设我有一个案例class定义如下:
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
的 class,它被定义为
case class Computer(make: String, RAM: int, clockSpeed: Double)
我想为它的所有值打印相同的内容。我想要这样的东西:
make = makeOfComputer
RAM = RAMOfComputer
clockSpeed = speedOfComputer
与其将上述 toString
函数复制、粘贴和改编到 Computer
class,我宁愿将其抽象化,以便它可以在任何情况下使用 class.
我有一些想法可以使用
CaseClassType.unapply(caseClassInstance).get.productIterator.toList
获取案例class和
的值 classOf[CaseClass].getDeclaredFields.map(_.getName)
获取字段名称。这意味着我可以在完全不知道 case class 的实际结构的情况下找到 case class 中所有值的列表以及所有字段名称的列表。
一旦我有了这两个集合,我就可以递归地遍历它们来创建字符串。我在想像下面这样的东西可以工作但不幸的是scala不允许 case classes 从其他 case classes.
继承case class StringifiableCaseClass(){
override def toString: String =
//get the values and the fieldnames and create a string
我所要做的就是让案例 classes 扩展 StringifiableCaseClass
,他们将能够创建正确的字符串。
之所以要用case class作为基本类型是因为我可以用
classOf[this.type]...etc
和
this.type.unapply(this)...etc
在 StringifiableCaseClass
中。
关于如何实现我想要的东西的任何想法我不能将案例 classes 扩展到其他案例 classes?
如果我正确理解了你的用例,你可以使用 Cats 默认 Show
type-class 或者,如果你需要更多自定义行为,你可以直接使用泛型推导 Shapeless
实现你所追求的。
有关 Cat Show
更简单的场景,请阅读 here。
如您所见,它的语法可让您对范围内具有 Show[T]
的任何 T
执行 myObject.show
。
如果您想要更可定制的行为,您可以尝试直接使用 Shapeless。在 this example Show
type-class and you can see it running here.
鉴于这些案例 classes:
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)))
基本实现不一定是案例class。让它成为一个特征,然后你的案例 classes 都可以扩展它。
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
...等等