为什么在此代码中对重载定义的引用不明确?

Why there is ambiguous reference to overloaded definition in this code?

为什么这段代码中对重载定义的引用不明确?

class A {
  def m(a1: A, o2: Any): A = {
    print("1")
    a1
  }

  def m(a1: A, a2: A): A = {
    print("2")
    a1
  }

  def m(o1: Any, o2: Any): Any = {
    print("3")
    o1
  }

  def m(o: Any): Any = {
    print("4")
    o
  }
}

class B extends A {
  def m(b1: B, o2: Any): A = {
    print("5")
    b1
  }

  override def m(a: A, o2: Any): B = {
    print("6")
    this
  }

  override def m(o1: Any, o2: Any): Any = {
    print("7")
    o1
  }

  def m(i: Int): Unit = { print("8") }
}

val a = new A
val b = new B

b.m(a, a)

以上代码编译错误:

ambiguous reference to overloaded definition,

[error] both method m in class B of type (a: A, o2: Any)B

[error] and method m in class A of type (a1: A, a2: A)A [error] match argument types (A, B)

但我的理解是method m in class A of type (a1: A, a2: A)A更具体 比 method m in class B of type (a: A, o2: Any)B

如有任何提示,我们将不胜感激。

你完全正确 - A 中的 m 版本更具体,这实际上就是问题所在。

由于您实际上是在 b 的实例上调用 m(即 b.m(a, a)),编译器首先检查是否存在与 [=15] 中的签名匹配的方法=].由于 B 确实有一个方法可以通过类型检查(即 m(a: A, o2: Any): B),所以到目前为止一直很好。但是,虽然编译器还检查超类 A,但它找到了更具体的 m 版本(即 m(a1: A, a2: A): A)。

问题是您在 B 的实例上调用了 m,但您明确要求编译器找到一个采用两个 A 类型参数的方法。编译器现在不确定您实际打算执行哪个版本,因此会出现编译错误。

更好的编译信息可能是:

"Hey I found a version of m further up the hierarchy in A that better meets your requirements but I see you are explicitly invoking m on a B (not an A) so I don't really know which one to choose now - you better check this otherwise if I just choose one you may not get the results you were after at runtime."