为什么Scala编译器不允许使用默认参数的重载方法?

虽然可能有这种方法重载可能会变得模糊的有效情况,但是为什么编译器不允许在编译时和运行时都不明确的代码呢?

例:

// This fails: def foo(a: String)(b: Int = 42) = a + b def foo(a: Int) (b: Int = 42) = a + b // This fails, too. Even if there is no position in the argument list, // where the types are the same. def foo(a: Int) (b: Int = 42) = a + b def foo(a: String)(b: String = "Foo") = a + b // This is OK: def foo(a: String)(b: Int) = a + b def foo(a: Int) (b: Int = 42) = a + b // Even this is OK. def foo(a: Int)(b: Int) = a + b def foo(a: Int)(b: String = "Foo") = a + b val bar = foo(42)_ // This complains obviously ... 

有什么理由不能放松这些限制吗?

特别是在将大量重载的Java代码转换为Scala时,默认参数是非常重要的,通过一个Scala方法replace大量的Java方法并不好,因为spec /编译器强加了任意的限制。

我想引用卢卡斯·瑞兹(从这里 ):

原因是我们需要一个确定性的命名scheme来生成返回默认参数的方法。 如果你写

def f(a: Int = 1)

编译器生成

def f$default$1 = 1

如果在同一个参数位置上有两个带有默认值的重载,我们需要一个不同的命名scheme。 但是我们希望通过多次编译运行保持生成的字节码稳定。

未来Scala版本的解决scheme可能是将非默认参数的types名称 (在方法开头的那些消除重载版本的歧义)整合到命名模式中,例如在这种情况下:

 def foo(a: String)(b: Int = 42) = a + b def foo(a: Int) (b: Int = 42) = a + b 

它会是这样的:

 def foo$String$default$2 = 42 def foo$Int$default$2 = 42 

有人愿意写一个SIPbuild议 ?

对于重载分辨率与默认参数的交互,要获得一个可读和精确的规范是非常困难的。 当然,对于许多个别情况,像这里介绍的情况一样,很容易说出会发生什么。 但这还不够。 我们需要一个规格来决定所有可能的angular落案例。 重载parsing已经很难指定了。 在混音中添加默认参数会使其更难。 这就是为什么我们select分开这两个。

我无法回答你的问题,但是这是一个解决方法:

 implicit def left2Either[A,B](a:A):Either[A,B] = Left(a) implicit def right2Either[A,B](b:B):Either[A,B] = Right(b) def foo(a: Either[Int, String], b: Int = 42) = a match { case Left(i) => i + b case Right(s) => s + b } 

如果你有两个只有一个参数不同的非常长的参数列表,这可能是值得的麻烦…

其中一种可能的情况是

 def foo(a: Int)(b: Int = 10)(c: String = "10") = a + b + c def foo(a: Int)(b: String = "10")(c: Int = 10) = a + b + c 

编译器会困惑要调用哪一个。 为了防止其他可能的危险,编译器最多允许一个重载方法有默认参数。

只是我的猜测:-)

我的理解是,在编译的类中可能会有默认参数值的名称冲突。 我已经看到了在几个线程中提到的这些方面的东西。

命名的参数规范在这里: http : //www.scala-lang.org/sites/default/files/sids/rytz/Mon,%202009-11-09,%2017 :29/named-args.pdf

它指出:

  Overloading If there are multiple overloaded alternatives of a method, at most one is allowed to specify default arguments. 

所以,就目前而言,这是不行的。

你可以做一些你可能用Java做的事情,例如:

 def foo(a: String)(b: Int) = a + (if (b > 0) b else 42) 

如果你调用foo()应该调用哪一个?