2014-02-15 36 views
6

的设置在这个例子中(斯卡拉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列举候选人时,不应该考虑每次转换是否真的有效?

回答

4

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

我要说的是,你的代码打破One-at-a-time Rule导致破Non-Ambiguity RuleA : 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)的分辨率两类XY看起来是一样的编译器,因此是不明确的。正如链接文档所说:“出于理智考虑,编译器在已经处于尝试另一隐式中间时不会插入其他隐式转换。”

+0

我可以抽象地购买该解释,但我不遵循在细节上。一次一个表示隐式转换不构成,这不会在这里发生,否则'new X(“”)。foo()'不会编译。非模糊性是关于“没有其他*可能*转换插入”的具体内容。 –

+0

我同意你的看法,并很乐意看到更具体的答案。无论如何,这个问题很好 –

相关问题