为什么在Scala中编译以下(玩具)示例没有任何问题,用于决定选择哪个隐式转换的规则是什么?
object test1 {
class MyInt(val v: Int) {
def +(other: MyInt) = new MyInt(v + other.v)
override def toString = v.toString
}
class MyIntMod10(vparam: Int) {
val v = vparam % 10;
def +(other: MyIntMod10) = new MyIntMod10(v + other.v)
override def toString = v.toString
}
val a = new MyInt(7); //> a : test1.MyInt = 7
val b = new MyIntMod10(7); //> b : test1.MyIntMod10 = 7
implicit def toIntMod10(x: MyInt) = new MyIntMod10(x.v)
//> toIntMod10: (a: test1.MyInt)test1.MyIntMod10
val c1 = a + b //> c1 : test1.MyIntMod10 = 4
val c2 = b + a //> c2 : test1.MyIntMod10 = 4
implicit def toInt(x: MyIntMod10) = new MyInt(x.v) //> toInt: (b: test1.MyIntMod10)test1.MyInt
val c3 = a + b //> c3 : test1.MyInt = 14
val c4 = b + a //> c4 : test1.MyIntMod10 = 4
}
由于含糊不清,我预计最后两行会产生编译时错误,但他们不会这样做。 (据我所知,c1和c3的值不同,直接显示了计算c3时的模糊性!如果我错了,请纠正我。)
我知道在当前版本的Scala中,编译器会解决一些模糊的隐式调用,但是我无法看到给定的示例代码是如何处理这些特殊情况之一的!
答案 0 :(得分:1)
如果行设置为c1
和c3
,则调用的+
方法是MyInt
上定义的方法。在这些情况下,编译器首先尝试将参数转换为+
方法(b
)为MyInt
。同样,对于c2
和c4
,调用的+
方法是MyIntMod10
上定义的方法,因此编译器会将a
转换为MyIntMod10
}}。
这适用于c2
,c3
和c4
,其中有适当的隐含可用。
对于c1
的情况,没有隐含(此时)将b
转换为MyInt
,因此它会寻找转换a
的方法使用+
方法可以将MyIntMod10
作为参数 - 并因此找到隐式转换为MyIntMod10
以应用于a
,将其转换为{ {1}}正如您所观察到的那样。