【问题标题】:Why can a non-applicable implicit conversion introduce ambiguity?为什么不适用的隐式转换会引入歧义?
【发布时间】:2014-02-15 07:14:42
【问题描述】:

本示例的设置(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 可以明确地应用从 StringX 的隐式转换:

"".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 在枚举候选者时是否不应该考虑每次转换是否真的有效?

【问题讨论】:

    标签: scala implicits


    【解决方案1】:

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

    我会说您的代码破坏了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 两个类在编译器看来是相同的,因此是模棱两可的。正如链接文档所说:“为了理智,当编译器已经在尝试另一个隐式转换时,它不会插入进一步的隐式转换。

    【讨论】:

    • 我可以抽象地购买那个解释,但我不关注细节。一次一个意味着不组合隐式转换,这不会在这里发生,否则new X("").foo() 不会编译。并且非歧义是特定于“没有其他可能的转换插入”。
    • 我同意你的观点,很高兴看到更具体的答案。无论如何,好问题。
    猜你喜欢
    • 2013-07-03
    • 2020-07-20
    • 2020-01-15
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2017-11-25
    • 2011-08-16
    • 1970-01-01
    相关资源
    最近更新 更多