在scala varargs中强制单个参数

mon*_*ack 18 scala mockito

给定一个带有两种方法的java类(取自mockito):

OngoingStubbing<T> thenReturn(T value);

OngoingStubbing<T> thenReturn(T value, T... values);
Run Code Online (Sandbox Code Playgroud)

如果我从scala调用

....thenReturn("something")
Run Code Online (Sandbox Code Playgroud)

我收到一个错误:

Description Resource    Path    Location    Type
ambiguous reference to overloaded definition, both method thenReturn in trait OngoingStubbing of type (x$1: java.lang.Object, x$2: <repeated...>[java.lang.Object])org.mockito.stubbing.OngoingStubbing[java.lang.Object] and  method thenReturn in trait OngoingStubbing of type (x$1: java.lang.Object)org.mockito.stubbing.OngoingStubbing[java.lang.Object] match argument types (java.lang.String)
Run Code Online (Sandbox Code Playgroud)

我无法弄清楚如何解决这个问题.

Ste*_*eve 22

这是一个已知的Scala-Java互操作性问题,但遗憾的是它不在FAQ中.这是描述问题Scala票证.基本上,当您提供单个参数时,这两种方法都适用,并且Scala编译器当前没有任何启发式方法来决定哪一个是"更具体"的.Alexey Romanov始终使用varargs版本的方法是一个很好的解决方法:

thenReturn("something", Nil: _*)
Run Code Online (Sandbox Code Playgroud)

还有一个问题与JCommander遇到类似的问题.其中一个答案给出了使用结构类型的巧妙解决方法.这种方法将在幕后使用反射,因此您可能想也可能不想走那个方向.对于您的用例,它看起来像:

type useSingleArgVersion = { def thenReturn(value: AnyRef): OngoingStubbing }
(...).asInstanceOf[useSingleArgVersion].thenReturn("something")
Run Code Online (Sandbox Code Playgroud)

最后,有一个类似的问题与mokito遇到类似的问题.它并没有真正提供任何变通方法,但如果您对发生这种情况的原因感兴趣,它确实会更详细地描述问题.


Ale*_*nov 13

如果调用vararg版本是可以接受的,

thenReturn("something", Nil: _*)
Run Code Online (Sandbox Code Playgroud)

现在想不出没有varargs的方法来调用方法.


psp*_*psp 13

这些答案都是错误的问题.区别很小,但这与链接票证中的问题不同.那个确实要求不合理的体操称为非varargs方法.对于这个,以下就足够了.

thenReturn[String]("something")
Run Code Online (Sandbox Code Playgroud)

或者,如果您由于某种原因不想这样做,则不需要类型别名和强制转换.您可以直接使用结构类型归属.

(this: { def thenReturn[T](s: T): OngoingStubbing[T] }).thenReturn("something")
Run Code Online (Sandbox Code Playgroud)

这里的问题是在重载和多态的交叉处的类型推断 - 一种方法更具体,但scalac没有弄清楚哪种方法.由于重载和元组转换之间的相互作用,SI-2991中的问题是真正的模糊性 - 两者都不是更具体.

  • 问题是,当你正在对一个返回java.lang.Object(又名为AnyRef)的方法进行存根时,你会被Scala搞砸. (2认同)