'模糊引用过载定义'用于没有清单的隐式转换

时间:2013-10-10 20:02:50

标签: scala

如果我不包含Manifest,则会出现隐式转换的编译错误:

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的隐式Manifest:

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的清单”错误,这可以通过显式创建包装类来消除;但是,如果我们能够从那个理想的隐式转换中获得Manifest。为什么它是必需的,还是有另一种方法可以在避免清单的同时完成同样的事情?

2 个答案:

答案 0 :(得分:1)

这是由scala自动将Ints升级为Double引起的,这使隐式转换变得模糊不清。当包含清单时,它会创建一个隐式参数,使得函数解析变得明确,就像DummyImplicit隐式参数用于解决因Ivan所提到的类型擦除而导致的过载函数歧义。

答案 1 :(得分:0)

我相信这是因为一旦转换为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
}

清单是我理解失败的地方,因为我从来没有处理过很多,但我想它预先存在类型,以便方法重载工作。

你可以使用宏来解决这个问题,我相信,虽然这样会阻止在编译器不确定的任何内容上调用Funcs.f()是Int或Double。