用函数值覆盖特征方法

dte*_*ech 2 inheritance scala

说我有这样的特质

trait X {
  def foo(param: String): Int
}
Run Code Online (Sandbox Code Playgroud)

我想用函数值覆盖它,我必须这样做:

class XImpl extends X {
  private val fooF: String => Int = ???
  override def foo(param: String): Int = fooF(param)
}
Run Code Online (Sandbox Code Playgroud)

因为以下不起作用

class XImpl extends X {
  override val foo: String => Int = ???
}
/*
       error: class XImpl needs to be abstract. Missing implementation for:
         def foo(param: String): Int // inherited from trait X
                                            ^
       error: value foo overrides nothing.
       Note: the super classes of class XImpl contain the following, non final members named foo:
       def foo(param: String): Int
*/
Run Code Online (Sandbox Code Playgroud)

是否可以以某种方式直接实现/覆盖具有函数值的 trait 方法并避免转发器?

Tim*_*Tim 5

简单的答案是,您不能使用函数值覆盖方法,因为它们的类型不同。

必须在类的特定实例上调用方法(即使方法本身不使用该类中的任何字段)。

一个函数值是独立的,可以在没有任何附加信息的情况下被调用。

可以使用eta 扩展 将方法转换为函数值x.foo _。这将创建一个函数值,其中嵌入了类值。

val x: X = ???
val etaFoo: String => Int = x.foo _
Run Code Online (Sandbox Code Playgroud)

在这种情况下,Scala 实际上会为您进行 eta 扩展,因此它_是可选的,但在更复杂的用途中是必需的,并且将其保留在那里是一种很好的做法,以便表明 eta 扩展正在发生。

要将函数值转换为方法,您需要定义一个方法,如问题所示。


Eta 扩展适用于具有多个参数的方法:

trait X2 {
  def foo2(p1: String, p2: Int): String
}

val x2: X2 = ???
val etaFoo2: (String, Int) => String = x2.foo2 _
Run Code Online (Sandbox Code Playgroud)