为什么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()
应该调用哪一个?