Scala递归泛型:父[Child]和Child [Parent]

时间:2010-10-07 22:48:34

标签: generics scala types

更新:澄清并扩展,因为原始问题已经过度简化

我需要一对特征,每个特征引用另一个特征,使父类和子类必须相互关联。

trait Parent [C <: Child] {
  def foo(c: C)
}

trait Child [P <: Parent] {
  def parent: P = ...
  def bar = parent.foo(this)
}

这样实现类必须成对出现:

class ActualParent extends Parent [ActualChild] {
  def foo(c: ActualChild) = ...
}

class ActualChild extends Child [ActualParent] {
}

不幸的是,编译器不喜欢这些特性,因为泛型类型不完整。而不是C <: Child它需要说C <: Child[ 某事 ]。如果不指定它们也不起作用:

trait Parent [C <: Child[_]] {
  def foo(c: C)
}

trait Child [P <: Parent[_]] {
  def parent: P = ...
  def bar = parent.foo(this)
}

它现在在parent.foo(this)行上抱怨,因为它不知道this的类型正确。调用parent以获得正确类型的Parent[this.type]类型必须为foo

我认为必须有一种方式来引用一个对象自己的类型?或者是一个需要自己的类型?


更新 :继@ Daniel的回答之后,我尝试在子项中使用抽象类型成员来声明父类型的泛型类型,如下所示:

trait Parent [C <: Child] {
  def foo(c: C)
}

trait Child {
  type P <: Parent[this.type]

  def parent: P = ...
  def bar = parent.foo(this)
}

当我尝试实现它时,这不起作用:

class ActualParent extends Parent [ActualChild] {
  def foo(c: ActualChild) = ...
}

class ActualChild extends Child {
  type P = ActualParent
}

给出以下错误:

overriding type Parent in trait Child with bounds >: Nothing <: Parent[ActualChild.this.type]
type Parent has incompatible type

这是什么意思?

5 个答案:

答案 0 :(得分:5)

您可以使用http://programming-scala.labs.oreilly.com/ch13.html中提供的方法:

abstract class ParentChildPair {
  type C <: Child
  type P <: Parent

  trait Child {self: C =>
    def parent: P
  }

  trait Parent {self: P =>
    def child: C
  }
}

class ActualParentChildPair1 {
  type C = Child1
  type P = Parent1

  class Child1 extends Child {...}

  class Parent1 extends Parent {...}
}

答案 1 :(得分:3)

可以使用抽象类型成员完成。

class Parent {
  type C <: Child
  def child: C = null.asInstanceOf[C]
}

class Child {
  type P <: Parent
  def parent: P = null.asInstanceOf[P]
}

答案 2 :(得分:3)

继@ Daniel的答案之后,我可以在子节点中使用抽象类型成员来声明父类型的泛型类型,如下所示:

trait Parent [C <: Child] {
  def foo(c: C)
}

trait Child {
  type P <: Parent[this.type]

  def parent: P = ...
  def bar = parent.foo(this)
}

this.type不能直接在泛型中使用,但在参数中似乎没问题。这种方法比周围的抽象类少得多,并且允许更灵活的用途,例如也是父母的孩子。

答案 3 :(得分:1)

您可以撰写C <: Child[_]

答案 4 :(得分:1)

即使没有成功,我也会记录这条大道作为答案。

使用抽象类型成员,引用返回this.type的类型的状态界限:

trait Parent {
  type C <: Child { type P <: this.type }
  def foo(c: C)
}

trait Child {
  type P <: Parent { type C <: this.type }
  def parent: P
  def bar = parent.foo(this)
}

class ActualParent extends Parent {
  type C = ActualChild
  def foo(c: ActualChild) = println("Hello")
}

class ActualChild extends Child {
  type P = ActualParent
  def parent = new ActualParent
}

这里的问题是编译器没有将this与父类的子类型连接,因此调用parent.foo(this)会导致:

type mismatch
found : Child.this.type (with underlying type Child)
required: _3.C where val _3: Child.this.P