2011-04-06 31 views
10

sum方法对TraversableOnce签名是如下:为什么这个调用隐含地含糊不清?

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 

我相信,这事做的事实和声明了一个新的类型参数B >: A显然是,见下面编辑),但我仍然为什么有些困惑在第一个例子中可以明确地发现ing,但不是第二个?

编辑 - 解决subsub的空洞的评论(下同)

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

这是模棱两可的任何调用隐式。 'scala> Predef.implicitly :6:error:含糊隐含值: 这两种方法都符合类型为[A,A] <:[[A,A] 的对象Predef和类型为>> scala的对象Predef中的方法stringCanBuildFrom。 collection.generic.CanBuildFrom [String,Char,String] 匹配预期类型T Predef.implicitly'。所以可能的底层含义是“没有找到任何合适的隐含的东西在这里,请帮助!” – subsub 2011-04-06 12:26:55

+0

@subsub - 请参阅我的编辑。这正是发生了什么;我在问为什么隐含的调用被推断为导致模棱两可的隐含。如果在应付方式中存在匹配的隐含值,为什么no-param调用会有类似的问题? – 2011-04-06 13:27:04

+0

如果我的评论是蠢话,你为什么编辑你的问题? (bs:TraversableOnce [A]){def sum(implicit num:Numeric [A]):A = bs.foldLeft(num.zero)(num.plus)}这是另一个: ; (新Bs(1到10))。sum(隐含地)' – subsub 2011-04-06 14:00:29

回答

5

短的情况下回答:因为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 
      ^