Scala:为super方法添加可选参数

时间:2014-08-08 16:32:38

标签: scala inheritance

我正在尝试实施如下特征:(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会做出这些选择呢?

2 个答案:

答案 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
}