Scala 3 中使用 Varargs 的模糊重载

Ambiguous Overload in Scala 3 with Varargs

我有以下代码。

object example {

  def foo(a: Any) = "Object"

  def foo(a: String, args: String*) = "String"

  def main() = {
    println(foo("ABC")) // Should print "String"
  }

}

在 Scala 2 中,这段代码工作正常。当我用一个字符串参数调用 foo 时,两个重载都是有效的,但 String 一个更具体,所以它被调用。在 Scala 3 中,这是不明确的。

-- [E051] Reference Error: overloads.scala:9:12 --------------------------------------------------------------------
9 |    println(foo("ABC"))
  |            ^^^
  |            Ambiguous overload. The overloaded alternatives of method foo in object example with types
  |             (a: String, args: String*): String
  |             (a: Any): String
  |            both match arguments (("ABC" : String))

等效代码(两个重载,其中一个更具体并且具有 vararg 参数)也适用于 Java。 Scala 3 中到底发生了什么变化,使这个特定的调用变得模棱两可?这种行为是故意的吗?在这种情况下,我如何告诉 Scala 调用哪个重载?


就其价值而言,我很清楚在 Scala 中强烈反对方法重载。在我的实际代码中,我正在与具有重载 .append 方法的 Java 构建器 class 交互,因此我无法控制函数签名。

this PR, in particular in this comment 中提到了此行为。我不知道这是否会“修复”或者是否完全符合预期。

注意以下不是歧义:

def foo(s: String)
def foo(a: String, other: String*)
foo("fine!")

使用 def foo(s: Any),您可以显式 select 一个重载或另一个重载,如下所示:

foo("fine": Any) // calls foo(Any)
foo("fine", Nil: _*) // calls foo(String, String*) with an empty vararg

PS:我不会说重载是“强烈反对”的,但我们必须小心并承认某些情况对编译器和人类来说是模棱两可的。对我来说,foo("") 应该指的是哪个定义并不明显,所以在这种情况下更明确一点并不完全疯狂。