'ambiguous reference to overloaded definition'不带清单的隐式转换


如果我

不包含清单,则会出现隐式转换的编译器错误:

import scala.language.implicitConversions
abstract class Thing[+A] {
  def get:A
}
case class SubThing[+A](a:A) extends Thing[A] {
  def get = a
}
object Thing {
  implicit def anyToThing[A](a:A):Thing[A] = SubThing(a)
}
object Funcs {
  def f(x:Thing[Int]) = x.get + 1
  def f(x:Thing[Double]) = x.get + 1.0
}
object Main {
  def main(args:Array[String]) = {
    println(Funcs.f(1))
  }
}

会给

error: ambiguous reference to overloaded definition,
       both method f in object Funcs of type (x: Thing[Double])Double
       and  method f in object Funcs of type (x: Thing[Int])Int
       match argument types (Int) and expected result type Any
println(Funcs.f(1))
              ^

但是,如果我在隐式转换中为 A 传递隐式清单:

import scala.language.implicitConversions
abstract class Thing[+A] {
  def get:A
}
case class SubThing[+A](a:A) extends Thing[A] {
  def get = a
}
object Thing {
  implicit def anyToThing[A:Manifest](a:A):Thing[A] = SubThing(a)
}
object Funcs {
  def f(x:Thing[Int]) = x.get + 1
  def f(x:Thing[Double]) = x.get + 1.0
}
object Main {
  def main(args:Array[String]) = {
    println(Funcs.f(1))
  }
}

使代码编译正常。为什么会这样呢?在我们的代码库中有一个真实的例子,如果您在泛型情况下依赖隐式转换,它会给出很多"T 没有清单"错误,这些错误是通过显式创建包装类来消除的;但是,如果我们可以从隐式转换中获取清单,那将是理想的。为什么需要它,或者有没有另一种方法可以在避免清单的同时完成同样的事情?

这是

由于 scala 自动将 Ints 提升为 Double,这使得隐式转换变得模糊不清。包含清单时,它会创建一个隐式参数,导致函数解析变得明确,就像 DummyImplicit 隐式参数用于对抗重载函数的多义性一样,这是由于 Ivan 提到的类型擦除造成的

我相信

发生这种情况是因为一旦转换为 Thing,类型擦除就会启动,它不再是 Thing[Int] 或 Thing[Double],而是一个 Thing[_],因此以下方法重载不起作用。

object Funcs {
  def f(x:Thing[Int]) = x.get + 1
  def f(x:Thing[Double]) = x.get + 1.0
}

清单是我的理解有点崩溃的地方,因为我从来没有处理过它,但我想它预示了类型,以便方法重载有效。

我相信你可以用宏来解决这个问题,尽管这会排除在编译器不确定是 Int 或 Double 的任何内容上调用 Funcs.f((。

最新更新