【发布时间】:2021-04-15 08:54:59
【问题描述】:
当转换发生在隐式类声明中时,编译器无法选择正确的隐式转换方法。在下面的示例中,我有一个 Foo[T] 类和一个隐式 Helper 类,它采用 Foo 并提供 print 方法。该打印方法调用show,它本身就是Foo 上的隐式转换提供的方法。
问题是有两种可能的转换提供show:一种将Foo[T] 转换为Bar[T],另一种将Foo[Array[T]] 转换为BarArray[T]。这个想法是,当我们有一个包含数组的Foo 时,我们希望应用更具体的BarArray 转换。据我了解,编译器首先选择最具体类型的转换。
这在正常上下文中有效,如下例所示,但在隐式 Helper 类中的 print 方法的上下文中中断。在那里,调用了相同的 show 方法,因此我希望应该应用相同的转换。但是,在这种情况下,编译器总是选择Bar 转换,即使它有Foo[Array[T]] 并且应该选择BarArray 转换。
出了什么问题?
最少的失败代码示例:
package scratch
import scala.language.implicitConversions
class Foo[T](val value: T) {}
object Foo {
implicit def fooToBar[T](foo: Foo[T]): Bar[T] = {
new Bar(foo.value)
}
implicit def fooArrayToBarArray[T](foo: Foo[Array[T]]): BarArray[T] = {
new BarArray(foo.value)
}
}
class Bar[T](val value: T) {
def show(): String = {
s"Bar($value)"
}
}
class BarArray[T](val value: Array[T]) {
def show(): String = {
value.map(v => s"Bar($v)").mkString(", ")
}
}
object Scratch extends App {
implicit class Helper[T](foo: Foo[T]) {
def print(): Unit = {
println(foo.show())
}
}
val foo0 = new Foo(123)
val foo1 = new Foo(Array(123, 456))
// conversions to Bar and BarArray work correctly here
println(foo0.show()) // Bar(123)
println(foo1.show()) // Bar(123), Bar(456)
// conversions called from within the implicit Helper class
// always choose the Bar conversion
foo0.print // Bar(123)
foo1.print // Bar([I@xxxxxxxx) <- should be Bar(123), Bar(456)
}
版本:
- Scala 2.12.10
- SBT 1.4.3
- JDK 1.8.0_241
【问题讨论】:
-
您需要为
Foo[Array[T]]提供第二个助手,但是我建议您停止使用如此多的隐式转换,而是寻找基于 typeclass 的解决方案。
标签: scala generics implicit-conversion implicit implicit-class