Scala - 绕过重写toString方法

时间:2015-07-21 11:25:18

标签: scala override tostring pretty-print

鉴于一个案例类 - 不幸的是 - 覆盖了toString方法,绕过该方法的任何方法?

即:

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

然后

foo

将产生

  

Hello World

如果我刚收到Foo(但不是foo),我可以对server { listen 80; server_name example.com; if ($args ~ "_escaped_fragment_=(.+)") { set $foo $1; rewrite ^ /snapshots$uri$foo?; } } 执行任何操作,以便打印

  

Foo(Hello World)

而不只是字符串?

3 个答案:

答案 0 :(得分:2)

不,你不能改变一个值的方法" ad-hoc"。您需要依赖类型类

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)"

答案 1 :(得分:2)

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

Repl测试:

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的方法。如果有的话,它表明在toString中依赖于Any方法并不是最好的设计,但是我们必须生活和使用大量代码(包括整个Java生态系统)做到了。

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

答案 2 :(得分:0)

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

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

您可以使用implicits使用自定义方法扩展Foo(请参阅0 __的答案中的类型类示例),但无法更改toString方法的实现。