为什么这个电话隐含含糊不清?

时间:2011-04-06 09:06:23

标签: scala implicit

sumTraversableOnce方法的签名如下:

def sum[B >: A](implicit num: Numeric[B]): B = foldLeft(num.zero)(num.plus)

我可以这样使用它:

scala> (1 to 10).sum
res0: Int = 55

在这种情况下,编译器正在注入Numeric[B]本身,因此在范围内必须有此类型的明确隐式值。如果我自己使用Predef.implicitly注入它,就会发生这种情况:

scala> (1 to 10).sum(implicitly)
<console>:6: error: ambiguous implicit values:
 both method conforms in object Predef of type [A]<:<[A,A]
 and method stringCanBuildFrom in object Predef of type => scala.collection.generic.CanBuildFrom[String,Char,String]
 match expected type T
   (1 to 10).sum(implicitly)
                 ^

为什么这个含糊不清?

我可以通过

消除歧义
scala> (1 to 10).sum(implicitly[Numeric[Int]])
res2: Int = 55

scala> (1 to 10).sum[Int](implicitly)
res3: Int = 55

我认为这与sum声明一个新的类型参数B >: A(显然是,见下面的编辑)这一事实有关,但我仍然感到困惑为什么在第一个例子中可以明确地找到某些东西而不是第二个例子?

编辑 - 以解决子网的愚蠢评论(下方)

scala> class As[A](as : A*) { 
 | def sum(implicit num : Numeric[A]) : A = as.foldLeft(num.zero)(num.plus) 
 | }
defined class As

scala> (new As(1, 2, 3, 4)).sum
res0: Int = 10

scala> (new As(1, 2, 3, 4)).sum(implicitly)
res1: Int = 10

所以,你可以看到隐含的任何调用都不是模糊的

1 个答案:

答案 0 :(得分:6)

简短回答:由于B >: A导致implicitly调用的结果类型无法推断。

更长的答案。如果缺少定义为implicit的参数,编译器将在当前作用域中搜索Numeric[B >: Int]类型的任何隐式值,并使用最具体的 - Numeric[Int]

但是,如果您将参数指定为implicitly(对implicitly [T] (implicit e: T) : T的调用),则必须首先解析类型参数T。 scala运行时显然没有这样做。

与调用它相同:

scala> var f = implicitly
 <console>:5: error: ambiguous implicit values:
 both method conforms in object Predef of type [A]<:<[A,A]
 and method stringCanBuildFrom in object Predef of type =>     scala.collection.generic.CanBuildFrom[String,Char,String]
 match expected type T
       var f = implicitly
               ^