Scala - 绕过覆盖的 toString 方法

Scala - bypass overridden toString method

假设 class 不幸地重写了 toString 方法,有什么方法可以绕过该方法?

即:

case class Foo(s:String){
    override def toString = s
}

然后

val foo = Foo("Hello World")
println(foo)

会产生

Hello World

如果我只得到 foo(但不是 Foo),我可以对 foo 做任何事情以便打印

Foo(Hello World)

而不只是字符串?

不,您不能更改值的方法"ad-hoc"。您将需要依赖类型 class 而不是

trait Show[A] {
  def show(x: A): String  // replaces the `toString` method
}

// allows you to write foo.show instead of implicitly[Show[Foo]].show(foo)
implicit class ShowOp[A](private val x: A) extends AnyVal {
  def show(implicit s: Show[A]): String = s.show(x)
}

case class Foo(s: String) { override def toString = s }

val foo = Foo("bar")
foo.show   // error -- no implicit for Show[Foo]

// define the Show type class for foo
implicit object ShowFoo extends Show[Foo] {
  def show(f: Foo) = s"Foo(${f.s})"
}

foo.show  // ok: "Foo(bar)"

您基本上是在询问是否可以在运行时修补特定实例的 toString 方法。

这在像 scala 这样的语言中是不可能的。

您可以使用隐含的自定义方法扩展 Foo(请参阅 0__ 的回答中的类型 class 示例),但是无法更改toString 方法。

如 0__ 所示,使用 Show 类型 class 是一个不错的选择。不幸的是 toString 是如此普遍(很多代码依赖它来格式化给定对象的字符串)以至于在很多情况下类型 class 对你没有任何好处。例如,如果您有一个 List[Foo],对其调用 toString 将调用 Foo.toString。使用类型 class 的正确解决方案是为列表定义一个实例,它本身将在 Foo 实例上调用 show。但这只会将问题推得更远,因为很可能您将此列表传递给您无法控制的某些第三方代码,并且这将调用 List.toString(而不是 Show.show ).在这种特定情况下,唯一可行的解​​决方案是将 Foo class 包装在您自己的 class(比如 MyFoo)中并在那里覆盖 toString。显然,这只有在您可以将 List|[Foo] 更改为 List[MyFoo]

时才有用
implicit class MyFoo(val foo: Foo) extends AnyVal {
    override def toString = s"Foo(${foo.s})"
}
object MyFoo {
 implicit def unwrap(myFoo: MyFoo): Foo = myFoo.foo
}

重复测试:

scala> val list1: List[Foo] = List(Foo("foo"), Foo("bar"))
list1: List[Foo] = List(foo, bar)

scala> val list2: List[MyFoo] = List(Foo("foo"), Foo("bar"))
list2: List[MyFoo] = List(Foo(foo), Foo(bar))

如您所见,list2 的字符串表示使用您自己的 toString 实现。 显然,这个解决方案并不理想。在许多情况下,它甚至可能完全不切实际(例如,您不能将 MyFoo 传递给需要 Foo 的方法)。如果有的话,它表明依赖 Any 中直接使用的 toString 方法并不是最好的设计,但是唉,我们不得不使用大量代码(包括整个 java 生态系统)就是这样做的。

与上述解决方案一样笨拙,如果您无法控制谁将调用 Foo.toString(这意味着您无法将该调用更改为其他任何内容,例如 Show.show)你可能无法做得更好。