当前位置: 首页 > 知识库问答 >
问题:

对重载定义的二义性引用-一个与两个参数

卫高谊
2023-03-14
object List {
  def apply[T](): List[T] = new Nil
  def apply[T](x1: T): List[T] = new Cons(x1, new Nil)
  def apply[T](x1: T, x2: T): List[T] = new Cons(x1, new Cons(x2, new Nil))
  def apply[T](elems: T*): List[T] = 
    elems.foldRight(List[T])((elem, l) => new Cons(elem, l))
}
List(1) // Error - Ambiguity 
List('a', 'b') // Works fine

scalac抱怨第一个实例化(对重载定义的引用不明确),因为单个参数和varargs方法都是相同特定的。

搜索stackoverflow时,我发现强制使用单参数方法是可能的。列表[Int](1)将使编译器使用def apply[T](x1:T)

我的问题是为什么第二个实例化匹配def applice[T](x1:T,x2:T)而没有额外的“提示”?换句话说,为什么双参数方法比varargs方法更具体,而单参数方法不是?

共有1个答案

邴奇逸
2023-03-14

为了回答您的问题,我们需要看看Scala编译器必须执行重载解析时会发生什么。SLS 6.23.3(用于Scala 2.9)中对此进行了描述。

让我们举一个稍微简单一点的例子:

object Test {
  def apply[T](x1: T) = "one arg"                      // A
  def apply[T](x1: T, x2: T) = "two args"              // B
  def apply[T](elems: T*) = "var-args: " + elems.size  // C
}

看看这三个电话:

Test(1) // fails, ambiguous reference, A and C both match arguments
Test[Int](1) // returns "one arg"
Test(1,2) // returns "two args", not "var-args: 2"
    null

然后编译器计算每个备选方案的相对权重。SLS规定

备选方案A相对于备选方案B的相对权重是从0到2的一个数字,定义

  • 1,如果A和B一样特定,则为0,并且
  • 1,如果A是从定义B的类或对象派生的类或对象中定义的,则为0,否则为0。

在这一点上,必须有一个选项比所有其他选项得分更高,否则就有歧义错误。我们可以忽略“已定义”的部分,它们是在同一个地方定义的。

    null

这也解释了为什么test[Int](1)成功调用one参数版本。最后两个替代方案是相同的,但是A的类型参数已经绑定到int,类型推断不能再更改它以适应C的参数。

最后,应用相同的逻辑可以说明为什么test(1,2)工作良好:

  • bc一样具体:您始终可以使用b的参数调用c
  • 但是C不如B:再多的类型推断也无法将一个seq放入接受两个参数的方法中。

所以apply[T](x1:T,x2:T)是最具体的,没有错误。

基本上,为了让var-arg和普通方法产生歧义,它们需要有相同数量的参数,以及在(至少)最后一个参数上欺骗类型推断的方法:

def apply[T](x1: T)
def apply[T](x: T*)

def apply[T](x1: Int, x2:T)
def apply[T](x1: Int, x: T*)
 类似资料:
  • 我试图使用mockito在scala中模拟,如下所示 会有什么问题?

  • 我最近开始学习Scala和Play框架,在阅读Play框架的Anorm文档时,我得到了以下代码片段: 却被编译错误卡住了:

  • 给定下面用Mockito模拟Scala类的代码,我会得到一个错误并且无法编译: 错误是: 对重载定义的引用不明确,类型为(x$1:class[common.testeable],x$2:org.Mockito.mocksettings)的对象Mockito中的方法mock和类型为(x$1:class[common.testeable],x$2:org.Mockito.stubbing.answhe

  • 我在swagger 2.0文件中定义了两个可重用参数: 然后在我的路由定义中(在本例中为GET),我尝试这样引用这两个: 如果我使用一个$ref,它似乎工作正常(没有编译错误),但是如果我尝试两个都使用,它会看着我: 此外,如果我在查询字符串中传递这些参数并输出<code>req.swagger。params</code>,我得到一个空对象。我做错了什么? 这是规范的完整SSCCE,生成相同的错误

  • 我有一个非常奇怪的问题,很简单,但我不明白问题是什么。 我有一个类,ClassA调用ClassB中的函数,比如- 类A是在我的applicationContext中定义的bean。类xml ClassB中的函数定义看起来像 IntelliJ没有指出任何语法问题,一切看起来都很正常。。。然而,当我试图编译时,Maven出现了一个异常 B类与a类位于不同的模块中,因此B类位于a类的pom中。作为依赖项

  • 为什么我有这个错误? 错误:(5,18)对重载定义的引用不明确,类型为(x$1:String)布尔的类String中的方法startsWith和类型为(x$1:String,x$2:Int)布尔的类String中的方法startsWith匹配预期的类型?水果过滤器(_.startswith==“AP”) 水果过滤器(_.startswith==“AP”)