我正在尝试实现如下特征:(1)
trait FooLike {
def foo(x: Int): Int
}
class Foo extends FooLike {
def foo(x: Int, y: Int = 0): Int = x + y
}
但是编译器提示方法 foo(x: Int): Int
未实现。
我能做到:(2)
class Foo extends FooLike {
def foo(x: Int): Int = foo(x, 0)
def foo(x: Int, y: Int = 0): Int = x + y
}
但是感觉像Java,我不喜欢它!有没有办法避免这个样板?
我认为 def foo(x: Int, y: Int = 0)
会在后台定义两个方法,但显然事实并非如此。到底发生了什么?
--- 编辑:更奇怪 ---
以下内容也是完全合法的:(3)
class Foo extends FooLike {
def foo(x: Int): Int = x - 1
def foo(x: Int, y: Int = 0): Int = x + y
}
虽然这看起来不合理(foo(4) = 3 while foo(4, 0) = 4)。
我认为授权(1)和禁止(3)本来是最合理的选择,但他们却做出了相反的选择。那么 Scala 为何做出这些选择呢?
最佳答案
在 Scala 中,无法使用默认参数覆盖不同类型签名的方法。这是因为默认参数的实现方式。默认参数是在应用方法的时间和位置插入的,因此只有一个版本的方法被定义。
根据SID-1: Named and Default Arguments ,当编译带有默认参数的方法 foo()
时,仅定义一个方法 foo()
,它接受所有参数。使用默认参数(例如 f.foo(xValue)
)的调用在编译时会转换为与以下内容等效的代码:
{
val x = xValue
val y = f.foo$default$2
f.foo(x, y)
}
foo$default$2
方法是一个隐藏方法,它不带任何参数,并将参数 #2 的默认值返回给方法 foo()
。
因此,虽然您可以为方法 foo(x: Int)
或方法 foo(x: Int) 编写完全相同的函数应用程序
,“在幕后”调用的方法不具有相同的类型签名。foo(xValue)
Int, y: Int = 0)
关于Scala:向 super 方法添加可选参数,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/25208080/