为什么这个调用隐含地不明确?
TraversableOnce
上的 sum
方法的签名如下:
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
有关(很明显,请参见下面的编辑),但我仍然很困惑为什么在第一个例子中可以明确地找到某些东西,但在第二个例子中却不能?
编辑 - 解决 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
因此,您可以看到任何隐式调用都不是不明确的
The signature of the sum
method on TraversableOnce
is as follows:
def sum[B >: A](implicit num: Numeric[B]): B = foldLeft(num.zero)(num.plus)
I can use it thus:
scala> (1 to 10).sum
res0: Int = 55
In this case, the compiler is injecting the Numeric[B]
itself, so there must be an unambiguous implicit value of this type in scope. If I use Predef.implicitly
to inject it myself, this happens:
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)
^
Why is this ambiguous?
I can make the ambiguity disappear either by
scala> (1 to 10).sum(implicitly[Numeric[Int]])
res2: Int = 55
Or
scala> (1 to 10).sum[Int](implicitly)
res3: Int = 55
I presume that this has something to do with the fact that sum declares a new type parameter B >: A
(it clearly is, see below edit), but I'm still confused about why something can be unambiguously found in the first example but not the second?
EDIT - to address subsub's inane comment (below)
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
So, you can see that it is not the case that any call to implicitly is ambiguous
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(1)
简短回答:因为
B >:无法推断
结果类型。隐式
调用的A更长的答案。当定义为
implicit
的参数丢失时,编译器将在当前范围中搜索Numeric[B >: Int]
类型的任何隐式值,并使用最具体的 -数字[Int]
。但是,如果您将参数指定为
implicitly
(调用implicitly [T] (implicit e: T) : T
),首先是类型参数T
> 必须解决。而 scala 运行时显然无法做到这一点。这与调用它是一样的:
Short answer: Because of
B >: A
resulting type forimplicitly
call can not be inferred.Longer answer. When argument defined as
implicit
is missing, compiler will search current scope for any implicit value of typeNumeric[B >: Int]
and will use the most specific -Numeric[Int]
.But if you specify argument as
implicitly
(a call to theimplicitly [T] (implicit e: T) : T
) first the type argumentT
must be resolved. And scala runtime clearly fails to do so.It is the same as calling this: