不幸的是,给定一个案例类覆盖了 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)
而不仅仅是字符串?
最佳答案
使用 Show
类型类(如 0__ 所示)是一个不错的选择。不幸的是 toString
如此普遍(很多代码依赖它来格式化给定对象的字符串),以至于在很多情况下类型类不会有任何好处。例如,如果您有一个 List[Foo]
,则对其调用 toString
将调用 Foo.toString
。使用类型类的正确解决方案是为列表定义一个实例,该实例本身将调用 Foo
实例上的 show
。但这只会把问题推得更远,因为很可能会发生这样的情况:您将此列表传递给您无法控制的某些第三方代码,并且该代码将调用 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
}
重复测试:
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
)你可能无法做得更好。
关于Scala - 绕过重写的 toString 方法,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/31537711/