隐含转换悖论

时间:2013-09-12 21:53:43

标签: scala

如果我尝试为基本类型定义隐式转换,那么它似乎不起作用。 E.g:

implicit def globalIntToString(a: Int) : String = { a.toString() + "globalhi" }
1.toInt + "hi"

上面的结果仍然只是“1hi”。

然而,似乎如果我参数化一个类或一个def然后传入隐式参数化的情况,那么它似乎工作。有谁知道原因是什么?例如。这是否与pretives的装箱/拆箱有关(例如,参数化的原语被装箱)?隐式只适用于引用类型而不是基本类型吗?

class typeConv[T] { implicit def tToStr(a: T) : String = { a.toString() + "hi" } }
class t[K](a: K)(tc : typeConv[K]) { import tc._; println(a + "cool"); println(1.toInt + "cool" ) }
new t(1)(new typeConv[Int])

2 个答案:

答案 0 :(得分:4)

这里有一些微妙的事情。 @yan已经解释了核心问题 - 我将尝试添加一些更具体的信息。

如上所述,1.toInt + "hi"永远不会使用任何隐式转换,因为Scala Int类实际上有一个方法+,它采用String参数。只有在原始类型中找不到匹配成员时,编译器才会查找隐式视图。

t课程中发生了一些更复杂的事情。 Scalac将查找从泛型类型K到具有+方法的任何类型的隐式转换,该方法采用String参数。此类转换将有两个候选人:您自己的tc.tToStr和Scala内置scala.Predef.any2stringadd

通常会使用any2stringadd,但在您的示例中,您会使用自己的转化。为什么它优先于any2stringadd

在隐式搜索期间,tc.tToStr被视为K => String类型的函数,而any2stringadd被视为类型Any => StringAdd的函数。我的猜测是编译器将K => String看作更具体的转换而不是Any => StringAdd,但有人必须通过对Scala语言规范的适当引用来确认它。 / p>

正如您所看到的,定义此类转换可能会导致许多奇怪的行为。我肯定会说,向String引入隐式转换是在寻找麻烦。

答案 1 :(得分:2)

这是因为Scala在Int类型上定义了一个+运算符,它接受一个String并且不需要解析隐式转换。此外,转换为String通常是个坏主意,因为您通常会使用自定义的一次性类型来定义您尝试添加的方法。