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) )

私はあちこちでキャストすることでそれを回避することができますが、親が親であることをコンパイラに伝えることができる方が良いでしょう。または多分私は何かが欠けています:)

編集-ジェネリック

ジェネリックはオプションではないことを言及するのを忘れました。この例は、実際には、より微妙な問題の単純化されたバージョンです。ジェネリックを使用すると、プログラムの2次成長につながります。ジェネリックスが常に実行可能な代替手段であるとは限らない理由を説明するリンクは次のとおりです。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
}

ちなみに、抽象メンバには sdefの代わりにs を使用してください。valそれらをサブクラスに実装する際の柔軟性が向上します。

于 2012-07-17T22:20:26.143 に答える
1

参考までに。sschaefにはそれを行うためのより良い方法があります。

これは、ScalaCRTPと自己型を使用してコンパイルされます。

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 に答える