Scala 2.7.7编译器/解释器中的虚假模糊引用错误?

时间:2010-01-29 01:08:29

标签: scala compiler-errors

任何人都可以解释下面的编译错误吗?有趣的是,如果我将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”)的

5 个答案:

答案 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)ab类型AB,则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]]: _*)