此示例的设置(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]
编译:
new X("").foo()
这不是:
new Y("").foo()
因为没有隐式T[String]
。
could not find implicit value for evidence parameter of type T[String]
new Y("").foo()
^
因此,我认为scalac可以毫不含糊地应用从String
到X
的隐式转换:
"".foo()
但我们得到:
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()
^
这是故意的吗? scalac是否不应该考虑每个转换在列举候选人时是否真的有效?
答案 0 :(得分:4)
我的非学术观点是隐含的设计并不意味着每次看起来应该有效。我认为这是一个好主意,否则你很容易陷入隐蔽的地狱。您可以通过添加更多隐式转换层来扩展您的示例。通过查看代码很难分辨实际调用哪个函数。有明确定义的规则,但我记得很简单,如果从代码中发现的事情并不明显,它就不起作用。
我会说你的代码中断One-at-a-time Rule会导致违反Non-Ambiguity Rule。 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() { } }
如果不解析“第二”隐式级别(方法参数e
),则类X
和Y
看起来与编译器相同,因此不明确。正如链接文档所说:“为了理智,当编译器已经在尝试另一个隐式转换时,编译器不会插入进一步的隐式转换。”