0

我想用抽象类型定义一个抽象递归数据结构。像这样的东西:

case class ParentA( name : String, children : List[ParentA] ) extends Parent {
    type PARENT = ParentA
}

case class ParentB( name : String, children : List[ParentB] ) extends Parent {
    type PARENT = ParentB
}

sealed abstract class Parent {
    // we'd like to Define Parent as a PARENT
    // something like: 
    // this : PARENT =>

    type PARENT <: Parent

    val name : String

    val children : List[PARENT]

    def findParent(name:String) : Option[PARENT] = {
        if( name == this.name ) {
            Some(this) // ouch
        } else {
            // re-ouch
            children.flatMap( f => f.findParent(name) )
        }
    }
}

val a2a : ParentA = ParentA("a",List(ParentA("a1",Nil),ParentA("a2",List(ParentA("a2a",Nil))))).findParent("a2a").get

当然这不会编译,因为编译器无法猜测 Parent.this 是 PARENT 。

error: type mismatch;
found   : Parent.this.type (with underlying type this.Parent)
required: Parent.this.PARENT
        Some(this)

并且

error: type mismatch;
found   : List[Parent.this.PARENT#PARENT]
required: Option[Parent.this.PARENT]
        children.flatMap( f => f.findParent(name) )

我可以通过在这里和那里进行转换来解决它,但最好能够告诉编译器 Parent 是 PARENT。或者也许我错过了一些东西:)

编辑 - 泛型

我忘了提到泛型不是一种选择。这个例子实际上是一个更微妙问题的简化版本。使用泛型将导致程序的二次增长。这是一个链接,解释了为什么泛型并不总是可行的替代方案:Scala:抽象类型与泛型

基本上我最好使用抽象类型 - 甚至既不使用抽象类型也不使用泛型 - 和强制转换。

4

2 回答 2

4

与@Debilski 提到的想法相同,但没有额外的类型参数:

case class ParentA(name: String, children: List[ParentA]) extends Parent[ParentA]

case class ParentB(name: String, children: List[ParentB]) extends Parent[ParentB]

sealed abstract class Parent[P <: Parent[P]] { this: P =>

  def name: String

  def children: List[P]

  def findParent(name: String): Option[P] =
    if (name == this.name) Some(this)
    else children.flatMap(_.findParent(name)).headOption
}

顺便说一句,抽象成员使用defs 而不是vals。它们在子类中实现它们时允许更大的灵活性。

于 2012-07-17T22:20:26.143 回答
1

仅供参考。sschaef有更好的方法来做到这一点。

这使用 Scala CRTP 和自类型进行编译。

case class ParentA(name : String, children : List[ParentA]) extends Parent[ParentA]

case class ParentB(name : String, children : List[ParentB]) extends Parent[ParentB]

sealed abstract class Parent[T] { this : T =>
    type PARENT = Parent[T] with T

    val name : String

    val children : List[PARENT]

    def findParent(name:String) : Option[PARENT] = {
        if( name == this.name ) {
            Some(this)
        } else {
            children.flatMap( f => f.findParent(name) ).headOption
        }
    }
}
val a2a : ParentA = ParentA("a",List(ParentA("a1",Nil),ParentA("a2",List(ParentA("a2a",Nil))))).findParent("a2a").get
于 2012-07-17T22:12:40.440 回答