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

Aar*_*rup 10 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")  
}
Run Code Online (Sandbox Code Playgroud)

错误:对重载定义的模糊引用,两个方法然后返回特征类型
java.lang.Object,java.lang.Object*)org.mockito.stubbing.OngoingStubbing [java.lang.Object]和方法返回特征OngoingStubbing的特征OngoingStubbing type(java.lang.Object)org.mockito.stubbing.OngoingStubbing [java.lang.Object]匹配参数类型(java.lang.String)when(t.get()).thenReturn("a")

Dan*_*ral 10

嗯,这是模棱两可的.我认为Java语义允许它,并且它可能值得一张要求在Scala中应用Java语义的票证.

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

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

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

如果你打电话f("foo"),A和B都适用.哪一个更具体?

  • 可以使用类型参数调用B (AnyRef),因此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
Run Code Online (Sandbox Code Playgroud)

现在,thenReturn("a")调用时没有元组转换.那不是问题.问题是,鉴于元组转换是可能的,两个版本都不thenReturn是更具体,因为传递给一个的任何参数也可以传递给另一个.


小智 7

在Mockito的特定情况下,可以使用为void方法设计的备用API方法:

doReturn("a").when(t).get()
Run Code Online (Sandbox Code Playgroud)

Clunky,但它必须这样做,因为Martin等人似乎不会为了支持Java的varargs而牺牲Scala.


Aar*_*rup 5

好吧,我想出了如何解决歧义(回想起来似乎有点明显):

when(t.get()).thenReturn("a", Array[Object](): _*)
Run Code Online (Sandbox Code Playgroud)

正如安德烈亚斯所指出的,如果模糊方法需要空引用而不是空数组,则可以使用类似的方法

v.overloadedMethod(arg0, null.asInstanceOf[Array[Object]]: _*)
Run Code Online (Sandbox Code Playgroud)

解决歧义.