有没有办法在Parent中定义类型T
,以便T
始终成为扩展类的实际类型(在本例中为Child
)?
在Parent
中,我想强制/声明T
始终是扩展类型,就好像我会在每个实际扩展类中编写type T="type_of_the_extending_class"
而不实际写下行type T=Child1
等中的Child1
所以Child1的方法只接受Child1对象作为参数,Child2的方法只接受Child2对象。有没有更简单的方法来强制执行此操作?有没有办法在每个type T=ChildX
课程中编写ChildX
?有没有这种样板的方法?
我一直在Scala书籍中寻找解决方案,但没有找到任何解决方案。
abstract class Parent{
type T<:Parent
def method(t:T)
}
class Child1 extends Parent{
type T=Child1
override def method(t:T)=t.child1method
def child1method=println("child1's method")
}
class Child2 extends Parent{
type T=Child2
override def method(t:T)=t.child2method
def child2method=println("child2's method")
}
答案 0 :(得分:7)
此问题的标准解决方案是F-bounded polymorphism(这不是特定于Scala的 - 您会在Java中使用它等):
trait Parent[T <: Parent[T]] {
def method(t: T)
}
class Child1 extends Parent[Child1] {
def method(t: Child1) = println("child1's method")
}
class Child2 extends Parent[Child2] {
def method(t: Child2) = println("child1's method")
}
作为旁注,Scala社区中有一些关于 F - 有界多态性的抱怨 - 例如Kris Nuttycombe说它是"tricky to get right and causes typing clutter in the codebase",我个人发现我使用了经过几年写Scala之后,它越来越少。但是,当您的程序体系结构导致您需要这种继承时,它正是该工作的正确工具。
this.type
(在评论中提到)的问题在于它不允许你完成大部分你想要做的事情 - 它太具体了:
scala> abstract class Parent {
| def method(t: this.type)
| }
defined class Parent
scala> class Child1 extends Parent {
| def method(t: this.type) = println("child1's method")
| }
defined class Child1
scala> val a = new Child1
a: Child1 = Child1@19517e9a
scala> val b = new Child1
b: Child1 = Child1@5737e545
scala> a.method(b)
<console>:12: error: type mismatch;
found : b.type (with underlying type Child1)
required: a.type
a.method(b)
^
我们可以传递给a.method
的唯一参数是a
本身。