在Scala中,假设类A和B具有通用方法,但没有继承任何公共接口:
class A {
def foo() {
println("A.foo")
}
}
class B {
def foo() {
println("B.foo")
}
}
我想要做的是定义一个特性,扩展任何具有foo()
方法的类。我试过这个:
type Fooable = {
def foo()
}
trait Q extends Fooable {
override def foo() {
println("before super.foo")
super.foo()
println("after super.foo")
}
}
(new A with Q).foo()
(new B with Q).foo()
但是,Scala编译器拒绝此代码时出现错误:
error: class type required but AnyRef{def foo(): Unit} found trait Q extends Fooable {
最好的解决方案是创建一个包含常用方法的接口,并修改类A和B以继承接口。不幸的是,我们无法修改这些类。这在Java库中很常见,例如:
java.sql.Connection.close()
和java.io.Closeable.close()
android.app.Activity.onDestroy()
和android.app.Service.onDestroy()
答案 0 :(得分:3)
你不能这样做。这是它的根本问题,引用你:
定义一个扩展任何类的特征
Scala要求 class 层次结构为树,这意味着其中的任何元素都将只有一个父类。它可以有许多父特征和许多祖先类,但是你要求的是严格违反Scala要求的层次结构。
现在,你在这里混合两个概念:名义类型,其中某种类型由其类或特征定义,以及结构类型,其中某种类型的东西是由什么方法定义的实现
然而,名义打字和结构打字相当不相容。事实上,在Scala之前,人们普遍认为两者不能同居,而事实上,Scala的结构打字版本非常有限。你可以这样做:
scala> def f(m: { def foo(): Unit }) = {
| println("before foo")
| m.foo()
| println("after foo")
| }
f: (m: AnyRef{def foo(): Unit})Unit
scala> f(new A)
before foo
A.foo
after foo
或者你可以将结构类型与自我类型结合起来,如下所示:
scala> trait Q { self: { def foo(): Unit } =>
| def bar() {
| println("before foo")
| foo()
| println("after foo")
| }
| }
defined trait Q
scala> (new A with Q).bar()
before foo
A.foo
after foo
scala> (new B with Q).bar()
before foo
B.foo
after foo
但是你不能从结构类型继承,因为继承是一种不同于名义类型的特性。并且,因为您无法继承结构类型,所以不能覆盖它,或者在祖先上调用它,这意味着trait Q
无法在foo()
上声明覆盖。
答案 1 :(得分:0)
自我回答:
在我知道我的问题没有确切的解决方案后,我提出了另一种方法来克服这个问题。 它不是一个完美的解决方案,但在某些情况下可能是一个合理的解决方法(在我的情况下: - )。
trait Fooable {
def beforeFoo() {}
def afterFoo() {}
}
trait Alice extends A with Fooable {
override def foo() {
beforeFoo()
super.foo()
afterFoo()
}
}
trait Bob extends B with Fooable {
override def foo() {
beforeFoo()
super.foo()
afterFoo()
}
}
trait Quest extends Fooable {
override def beforeFoo() {
println("before super.foo")
super.beforeFoo()
}
override def afterFoo() {
println("after super.foo")
super.afterFoo()
}
}
(new Alice with Quest).foo()
(new Bob with Quest).foo()
是的,我们应该使用Alice和Bob,而不是A和B.但是,在我的情况下,它可能会受到损害。