任何人都可以解释下面的编译错误吗?有趣的是,如果我将get()
方法的返回类型更改为String
,则代码编译得很好。请注意,thenReturn
方法有两个重载:一元方法和一个至少需要一个参数的varargs方法。在我看来,如果调用在这里是模棱两可的,那么它总是模棱两可的。
更重要的是,有没有办法解决歧义?
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")
}
错误:对重载定义的模糊引用, 两种方法然后返回特征类型的正在进行的训练 java.lang.Object中,java.lang.Object中*)org.mockito.stubbing.OngoingStubbing [java.lang.Object中] 和方法然后返回特征的OngoingStubbing类型 (java.lang.Object中)org.mockito.stubbing.OngoingStubbing [java.lang.Object中] 匹配参数类型(java.lang.String) 当(t.get())。thenReturn( “a”)的
答案 0 :(得分:9)
嗯,这是模棱两可的。我认为Java语义允许它,它可能值得一张要求在Scala中应用Java语义的票据。
ambiguitity的来源是这样的:vararg参数可以接收任意数量的参数,包括0.因此,当你写thenReturn("a")
时,你的意思是调用接收单个的thenReturn
参数,或者你的意思是调用接收一个对象加vararg的thenReturn
,将0个参数传递给vararg?
现在,发生了类似的事情,Scala试图找出哪种方法“更具体”。任何对细节感兴趣的人都应该在Scala的规范中查找,但这里是对这种特殊情况下发生的事情的解释:
object t {
def f(x: AnyRef) = 1 // A
def f(x: AnyRef, xs: AnyRef*) = 2 // B
}
如果你打电话给
f("foo")
,A和B. 适用。哪一个更多 具体?
- 可以使用
(AnyRef)
类型的参数调用B,因此A是 具体如B.- 由于元组,可以使用
(AnyRef, Seq[AnyRef])
类型的参数调用A. 转化,Tuple2[AnyRef, Seq[AnyRef]]
符合AnyRef
。所以 B与A一样具体。因为两者都是 与其他人一样具体 对f的引用含糊不清。
关于“元组转换”的事情,它是Scala最模糊的句法糖之一。如果您拨打电话f(a, b)
,a
和b
类型A
和B
,则f
接受(A, B)
但是有f
接受(Tuple2(A, B))
,然后参数(a, b)
将转换为元组。
例如:
scala> def f(t: Tuple2[Int, Int]) = t._1 + t._2
f: (t: (Int, Int))Int
scala> f(1,2)
res0: Int = 3
现在,调用thenReturn("a")
时没有进行元组转换。那不是问题。问题是,鉴于可以进行元组转换,thenReturn
的任何版本都不是更具体,因为传递给一个的任何参数也可以传递给另一个。
答案 1 :(得分:7)
在Mockito的特定情况下,可以使用为void方法设计的备用API方法:
doReturn("a").when(t).get()
笨拙,但它必须这样做,因为Martin等人似乎不会为了支持Java的varargs而牺牲Scala。
答案 2 :(得分:5)
好吧,我想出了如何解决歧义(回想起来似乎很明显):
when(t.get()).thenReturn("a", Array[Object](): _*)
正如安德烈亚斯所指出的,如果模糊方法需要空引用而不是空数组,则可以使用类似
的内容v.overloadedMethod(arg0, null.asInstanceOf[Array[Object]]: _*)
解决歧义。
答案 3 :(得分:4)
如果查看标准库API,您会看到此问题的处理方式如下:
def meth(t1: Thing): OtherThing = { ... }
def meth(t1: Thing, t2: Thing, ts: Thing*): OtherThing = { ... }
通过这样做,没有调用(至少有一个Thing参数)是不明确的,没有像Array[Thing](): _*
这样的额外绒毛。
答案 4 :(得分:3)
我在使用Oval(oval.sf.net)尝试调用它的validate()方法时遇到了类似的问题。
Oval定义了2个validate()方法:
public List<ConstraintViolation> validate(final Object validatedObject)
public List<ConstraintViolation> validate(final Object validatedObject, final String... profiles)
从Scala尝试:
validator.validate(value)
产生以下编译器错误:
both method validate in class Validator of type (x$1: Any,x$2: <repeated...>[java.lang.String])java.util.List[net.sf.oval.ConstraintViolation]
and method validate in class Validator of type (x$1: Any)java.util.List[net.sf.oval.ConstraintViolation]
match argument types (T)
var violations = validator.validate(entity);
Oval需要varargs-parameter为null,而不是空数组,所以我最终得到了它:
validator.validate(value, null.asInstanceOf[Array[String]]: _*)