1

如果我不包含 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 传递一个隐式清单:

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,那将是理想的。为什么需要它,或者是否有另一种方法可以在避免清单的同时完成同样的事情?

4

2 回答 2

1

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

于 2013-12-12T23:31:08.597 回答
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
}

清单是我的理解有点崩溃的地方,因为我从来没有过多地处理过它,但我想它会保留类型,以便方法重载起作用。

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

于 2013-10-10T20:41:27.973 回答