Scala 2.7.7 编译器/解释器中的虚假模糊引用错误? [英] Spurious ambiguous reference error in Scala 2.7.7 compiler/interpreter?

查看:15
本文介绍了Scala 2.7.7 编译器/解释器中的虚假模糊引用错误?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

谁能解释一下下面的编译错误?有趣的是,如果我将 get() 方法的返回类型更改为 String,代码编译得很好.请注意,thenReturn 方法有两个重载:一元方法和至少接受一个参数的可变参数方法.在我看来,如果这里的调用是模棱两可的,那么它总是模棱两可的.

更重要的是,有没有办法解决歧义?

import org.scalatest.mock.MockitoSugar导入 org.mockito.Mockito._特质事物{def get(): java.lang.Object}新 MockitoSugar {val t = 模拟[东西]当(t.get()).thenReturn("a")}

<块引用>

错误:对重载定义的引用不明确,这两种方法 thenReturn 在类型的特征 OngoingStubbing 中
java.lang.Object,java.lang.Object*)org.mockito.stubbing.OngoingStubbing[java.lang.Object]和方法 thenReturn 在 trait OngoingStubbing 类型(java.lang.Object)org.mockito.stubbing.OngoingStubbing[java.lang.Object]匹配参数类型(java.lang.String)when(t.get()).thenReturn("a")

解决方案

嗯,有歧义.我想 Java 语义允许这样做,它可能值得一张票,要求在 Scala 中应用 Java 语义.

歧义的来源是:一个vararg参数可以接收任意数量的参数,包括0.所以,当你写thenReturn("a")时,你的意思是调用thenReturn 接收一个参数,或者你的意思是调用 thenReturn 接收一个对象加上一个可变参数,将 0 个参数传递给可变参数?

现在,这种事情到底发生了什么,Scala 试图找出哪种方法更具体".任何对细节感兴趣的人都应该在 Scala 的规范中查找,但这里是对这种特殊情况下发生的情况的解释:

对象 t {def f(x: AnyRef) = 1//Adef f(x: AnyRef, xs: AnyRef*) = 2//B}

<块引用>

如果你调用 f("foo"),A 和 B适用.哪个更具体的?

  • 可以使用 (AnyRef) 类型的参数调用 B,所以 A 是和 B 一样具体.
  • 可以使用 (AnyRef,Seq[AnyRef]) 感谢元组转换,Tuple2[AnyRef,Seq[AnyRef]] 符合 AnyRef.所以B 和 A 一样具体.因为两者都是和另一个一样具体,对 f 的引用不明确.

至于元组转换"这件事,它是Scala最晦涩的语法糖之一.如果您调用 f(a, b),其中 ab 的类型为 AB,并且没有 f 接受 (A, B) 但有一个 f 接受 (Tuple2(A, B)),则参数(a, b)会被转换成元组.

例如:

scala>def f(t: Tuple2[Int, Int]) = t._1 + t._2f: (t: (Int, Int))Int标度>f(1,2)res0: 整数 = 3

现在,当 thenReturn("a") 被调用时,不会发生元组转换.那不是问题.问题是,考虑到元组转换是可能的,thenReturn 的两个版本都不是更具体,因为传递给一个的任何参数也可以传递给另一个.

Can anyone explain the compile error below? Interestingly, if I change the return type of the get() method to String, the code compiles just fine. Note that the thenReturn method has two overloads: a unary method and a varargs method that takes at least one argument. It seems to me that if the invocation is ambiguous here, then it would always be ambiguous.

More importantly, is there any way to resolve the ambiguity?

import org.scalatest.mock.MockitoSugar
import org.mockito.Mockito._

trait Thing { 
   def get(): java.lang.Object 
}

new MockitoSugar {   
   val t = mock[Thing]  

   when(t.get()).thenReturn("a")  
}

error: ambiguous reference to overloaded definition, both method thenReturn in trait OngoingStubbing of type
java.lang.Object,java.lang.Object*)org.mockito.stubbing.OngoingStubbing[java.lang.Object] and method thenReturn in trait OngoingStubbing of type (java.lang.Object)org.mockito.stubbing.OngoingStubbing[java.lang.Object] match argument types (java.lang.String) when(t.get()).thenReturn("a")

解决方案

Well, it is ambiguous. I suppose Java semantics allow for it, and it might merit a ticket asking for Java semantics to be applied in Scala.

The source of the ambiguitity is this: a vararg parameter may receive any number of arguments, including 0. So, when you write thenReturn("a"), do you mean to call the thenReturn which receives a single argument, or do you mean to call the thenReturn that receives one object plus a vararg, passing 0 arguments to the vararg?

Now, what this kind of thing happens, Scala tries to find which method is "more specific". Anyone interested in the details should look up that in Scala's specification, but here is the explanation of what happens in this particular case:

object t {
  def f(x: AnyRef) = 1 // A
  def f(x: AnyRef, xs: AnyRef*) = 2 // B
}

if you call f("foo"), both A and B are applicable. Which one is more specific?

  • it is possible to call B with parameters of type (AnyRef), so A is as specific as B.
  • it is possible to call A with parameters of type (AnyRef, Seq[AnyRef]) thanks to tuple conversion, Tuple2[AnyRef, Seq[AnyRef]] conforms to AnyRef. So B is as specific as A. Since both are as specific as the other, the reference to f is ambiguous.

As to the "tuple conversion" thing, it is one of the most obscure syntactic sugars of Scala. If you make a call f(a, b), where a and b have types A and B, and there is no f accepting (A, B) but there is an f which accepts (Tuple2(A, B)), then the parameters (a, b) will be converted into a tuple.

For example:

scala> def f(t: Tuple2[Int, Int]) = t._1 + t._2
f: (t: (Int, Int))Int

scala> f(1,2)
res0: Int = 3

Now, there is no tuple conversion going on when thenReturn("a") is called. That is not the problem. The problem is that, given that tuple conversion is possible, neither version of thenReturn is more specific, because any parameter passed to one could be passed to the other as well.

这篇关于Scala 2.7.7 编译器/解释器中的虚假模糊引用错误?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆