说我有这样的特征
trait X {
def foo(param: String): Int
}
我想用一个函数值覆盖它,我必须这样做:
class XImpl extends X {
private val fooF: String => Int = ???
override def foo(param: String): Int = fooF(param)
}
因为以下操作无效
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
*/
是否可以通过某种方式直接使用函数值实现/重写trait方法并避免使用转发器?
答案 0 :(得分:5)
简单的答案是,您不能使用函数值覆盖方法,因为它们不是同一类型。
必须在类的特定实例上调用方法(即使该方法本身不使用该类中的任何字段)。
函数值是独立存在的,无需任何其他信息即可调用。
可以使用eta expansion x.foo _
将方法转换为函数值。这样会创建一个函数值,其中嵌入了类值。
val x: X = ???
val etaFoo: String => Int = x.foo _
在这种情况下,Scala实际上会为您执行eta扩展,因此_
是可选的,但是在更复杂的用途中它是必需的,并且是将其保留在此处的良好实践,因此表明eta扩展正在发生。 / p>
要将函数值转换为方法,您需要定义一个方法,如问题所示。
Eta扩展适用于具有多个参数的方法:
trait X2 {
def foo2(p1: String, p2: Int): String
}
val x2: X2 = ???
val etaFoo2: (String, Int) => String = x2.foo2 _