2016-11-06 7 views
2

私はグラフのような階層構造でノードのようなオブジェクトを記述するための特性を書いています。私の作業のコードは以下の通りです:ジェネリック特性を拡張するクラスで、パラメータ `this 'を持つメソッドを呼び出すことができないのはなぜですか?

import org.scalatest.FlatSpec 

class DummyRoot extends RootNode 
class DummyNonRoot(override val parents: List[DummyRoot]) 
    extends NonRootNode(parents) 

class TestUtil extends FlatSpec { 

    "A RootNode" should "not have parents" in { 
    val dummyRoot = new DummyRoot 
    assert(dummyRoot.parents.isEmpty) 
    } 

    "A NonRootNode" should "have parents when constructed with them" in { 
    val dummyRoot = new DummyRoot 
    assert(dummyRoot.parents.isEmpty) 
    val dummyNonRoot = new DummyNonRoot(List(dummyRoot)) 
    dummyRoot.addChild(dummyNonRoot) 
    assert(dummyNonRoot.parents.contains(dummyRoot)) 
    assert(dummyRoot.children.contains(dummyNonRoot)) 
    }  
} 

は、しかし、私は2番目のテストで少し扱いに​​くいようにAPIを見つける:

trait Hierarchical[T <: Hierarchical[_]] { 
    // The parents will be a list of some arbitrary Hierarchical 
    val parents: List[Hierarchical[_]] = Nil 
    var children: List[Hierarchical[T]] = List() 

    def addChild(child: Hierarchical[T]): Unit = { 
    children ++= List(child) 
    } 
} 

abstract class NonRootNode(override val parents: List[Hierarchical[_]]) 
    extends Hierarchical[NonRootNode] { 
} 

abstract class RootNode extends Hierarchical[NonRootNode] { 
    final override val parents = Nil 
} 

私はこの動作を反映していくつかのテストを持っています。私は子供の親を既に指定しているので、ルートノードに子を明示的に追加する必要はありません。私はこれを公開APIから削除したいと思いますので、私はNonRootNodeのコンストラクタの動作を変更して、それぞれの親に対して呼び出すことを考えています。具体的には、私が書きたい:私はこの行を追加するとき

abstract class NonRootNode(override val parents: List[Hierarchical[_]]) 
    extends Hierarchical[NonRootNode] { 

    //for each parent, add `this` to its children 
    parents.map{p=>p.addChild(this)} 
} 

しかし、私は次のエラーを取得する:

Error:(19, 29) type mismatch; 
found : NonRootNode 
required: Hierarchical[_$3] 
    parents.map{p=>p.addChild(this)} 

私はなぜ私はこのコンパイラエラーを取得しています完全にはよく分かりません。 Hierarchical[_]の私の理解はです。Hierarchicalですが、間違いかもしれません。いずれにせよ、私は私が望む行動に近いと思う。私は間違って何をしていますか?

+0

子供が階層型[T]である間、両親はどのように '階層型 'になることができますか? –

+0

@ Jasper-M親は 'RootNode'または' NonRootNode'(または 'Hierarchical'の他の拡張子)でもかまいません。子供たちはすべて、それらが「階層的」であるように、同じタイプである。 – erip

答えて

3

Hierarchical[_]は、「任意の階層型」を意味するものではありません。これは、「固定されたタイプの階層型で、未知のもの」を意味します。

def foo: Hierarchical[_] = new Hierarchical[Int] 

作品例えば

:それは、Hierarchicalのいくつかの実装を返す関数、呼び出し側に知られていないその正確な型を宣言します。これは問題ありません。一方

は:仕事ない

def bar(h: Hierarchical[String]) = doStuff(h) 
bar(foo) 

ん:機能barは正確なタイプHierarchical[String]、とそれに渡されるのパラメータを望んでいることができ、そのタイプを持つことが保証され、それがタイプだありませんパラメータは不明です。

.addChildのメソッドはHierarchical[T](ここではTの値は不明です)で、同じタイプのパラメータが必要です。しかし、あなたが渡しているのはHierarchical[NonRootNode]です。 NonRootNodeが(不明の)Tと同じになることを保証する方法がないため、これは違法です。

+0

面白い - 理にかなっている。私の行動を達成するための簡単な方法はありますか?私は余分な型パラメータを追加しようとしましたが、少し煩雑になった相互再帰状況で自分自身を見つけました。 – erip

+1

まあ、私は確信しています、正確にあなたが実際にここで "自分の行動"を意味しています。 あなたの例ではそれを推論するのに十分ではありません。それで、それによって判断すると、 'Hierarchical'が全くパラメータ化される理由はありません。/ – Dima

+1

これは答えかもしれません - パラメータ化は不要です。テストを更新し、すぐに報告します。 – erip

関連する問題