为什么不适用的隐式转换会引入歧义?

Chr*_*tin 6 scala implicits

此示例的设置(Scala 2.10.3):

trait S[A]
trait T[A]
implicit class X[A : S](a: A) { def foo() { } }
implicit class Y[A : T](a: A) { def foo() { } }
implicit object I extends S[String]
Run Code Online (Sandbox Code Playgroud)

这编译:

new X("").foo()
Run Code Online (Sandbox Code Playgroud)

这不是:

new Y("").foo()
Run Code Online (Sandbox Code Playgroud)

因为没有隐含的T[String].

could not find implicit value for evidence parameter of type T[String]
              new Y("").foo()
              ^
Run Code Online (Sandbox Code Playgroud)

因此,我认为scalac可以毫不含糊地将隐式转换String应用于X:

"".foo()
Run Code Online (Sandbox Code Playgroud)

但相反,我们得到:

type mismatch;
 found   : String("")
 required: ?{def foo: ?}
Note that implicit conversions are not applicable because they are ambiguous:
 both method X of type [A](a: A)(implicit evidence$1: S[A])X[A]
 and method Y of type [A](a: A)(implicit evidence$1: T[A])Y[A]
 are possible conversion functions from String("") to ?{def foo: ?}
              "".foo()
              ^
Run Code Online (Sandbox Code Playgroud)

这是故意的吗?scalac是否应该考虑每个转换在枚举候选人时是否真的有效?

Rad*_*sky 4

我的非学术观点是,隐含的设计并不意味着每次看起来都应该有效。我认为这是一个好主意,否则你很容易陷入隐含的地狱。您可以通过添加更多层隐式转换来扩展您的示例。仅通过查看代码很难判断实际调用了哪个函数。有明确定义的规则,但我只记得,如果代码中发生的情况不明显,那么它就不起作用。

我想说的是,您的代码违反了“一次一次规则”,这会导致违反“非歧义性规则”A : S只是一个语法糖,可以重写为:

implicit class X[A](a: A)(implicit e: S[A]) { def foo() { } }
implicit class Y[A](a: A)(implicit e: T[A]) { def foo() { } }
Run Code Online (Sandbox Code Playgroud)

如果没有解决“第二”隐式级别(方法参数e),则两个类XY对于编译器来说都是相同的,因此是不明确的。正如链接文档所述:“为了理智起见,当编译器已经在尝试另一个隐式转换时,它不会插入进一步的隐式转换。