我正在尝试实施如下特征:(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而foo(4,0)= 4)。
我认为授权(1)和禁止(3)将是最合理的选择,但他们做出了相反的选择。那么为什么Scala会做出这些选择呢?
答案 0 :(得分:3)
使用默认参数无法在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(xValue)
或方法foo(x: Int)
编写相同的功能应用程序foo(x: Int, y: Int = 0)
,但在幕后调用方法""没有相同类型的签名。
答案 1 :(得分:1)
你正在扩展一个具有非实现方法的特征,你必须在扩展类中实现它,或者你可以在特征中实现它,如果你不需要foo
只有一个变量你可以做:
trait FooLike {
def foo(x: Int, y: Int): Int
}
class Foo extends FooLike {
def foo(x: Int, y: Int = 0): Int = x + y
}
但是我想你这样做,所以你必须给编译器一个实现,为了比较这种情况和Java,就像你扩展一个抽象类而你没有实现一个方法,编译器会抱怨要么实现方法,要么声明类抽象。
另一种想到并且相当合理的方法是在特征中实现该方法:
trait FooLike {
def foo(x: Int): Int = x
}
class Foo extends FooLike {
def foo(x: Int, y: Int = 0): Int = x + y
}
然后,如果你想添加一个混合了特征的新类,但是使用不同的方法实现,只需重写方法:
class AnotherFoo extends FooLike {
override def foo(x: Int): Int = x + 1
}