Scala:如何引用超类中扩展类的类型?

时间:2014-02-11 10:37:02

标签: scala types

有没有办法在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")
}

1 个答案:

答案 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本身。