2011-07-12 7 views
6

おはよう!次の質問が発生した開発中のよう 私は、Scalaのに非常に新しいです:型のパラメータ化または構造的サブタイプ化、または

私はT typeパラメータであるクラスツリー[T]を記述します。 しかし、Tは制約下しなければならない - それは2つの方法が必要です:(!): DEFキー()(:T X):T は、メソッドの実装 とDEF組合から派生し、いくつかのタイプであるを、Tはtypeパラメータと同じです。 私はこの制約は、いくつかの方法で表現することができるとします

キーと使用方法 組合(2つの形質があるため、これらの方法の独立した性質のものである)
  • と他の方法を持つ2つの特徴の1を定義する
    1. 構造的なサブタイピング
    2. 何か他のもの...

    は、どのように私は、各方法でそれを行うことができますか?他の方法が存在するか?

    また、これらのメソッドを単純な型(String、Intなど)に追加するのが簡単なのであれば、うまくいくでしょう。

  • 答えて

    5

    keyの構造タイプは定義できますが、unionの構造タイプは定義できません。構造型は、それ自身の外側で定義された抽象型を参照しないことがあります。だから、これは動作しません。

    trait Tree[T <: { def union(x: T): T }] 
    

    あなたはしかし、Treeの要素を利用できるようにしなければならない特性を定義することがあります。

    trait TreeVal[T] { 
        type A 
        def key: A 
        def union(x: T): T 
    } 
    

    これは2つの方法を使用することができます。最初に、クラスはそのインターフェイスを実装する必要があります。これは、どのクラスをキーとして使用できるかに重大な制約を課します。これは次のようになります:

    trait Tree[T <: TreeVal[T]] 
    

    また、このように、暗黙の型変換として提供することができます。これは、バインドビューと呼ばれるものを使用

    class IntVal(v: Int) extends TreeVal[Int] { 
        type A = Int 
        def key: A = v 
        def union(x: Int): Int = x + v 
    } 
    implicit def IntIsVal(v: Int): IntVal = new IntVal(v) 
    
    class Tree[T <% TreeVal[T]] // must be class, so it can receive parameters 
    

    。詳細を参照してください。しかし暗黙的な変換が定義されており、範囲がTreeValであるものを扱うことができると言えば十分です。また

    class Tree[T <% TreeVal[T]](node: T, left: Option[Tree[T]], right: Option[Tree[T]]) { 
        override def toString = "(%s < %s > %s)" format (left.getOrElse("o"), node.key, right.getOrElse("o")) 
    } 
    

    、あなたはいくつかの変更で、型クラスのパターンとそれを使用することができます:たとえば

    trait TreeVal[T] { 
        type A 
        def key(v: T): A 
        def union(x: T, y: T): T 
    } 
    class Tree[T : TreeVal] // must be class, so it can receive parameters 
    

    型クラスのパターンは、コンテキスト境界を使用しています。詳細はこちらをご覧ください。このスタイルは、以前のスタイルよりも一般的に好まれています。なぜなら、これは多くの点でより柔軟性があるからです。それにもかかわらず、どちらも機能します。この場合

    、一つはこのようにそれを使用します。

    implicit object IntVal extends TreeVal[Int] { 
        type A = Int 
        def key(v: Int) = v 
        def union(x: Int, y: Int) = x + y 
    } 
    
    class Tree[T: TreeVal](node: T, left: Option[Tree[T]], right: Option[Tree[T]]) { 
        val treeVal = implicitly[TreeVal[T]] 
        import treeVal._ 
    
        override def toString = "(%s < %s > %s)" format (left.getOrElse("o"), key(node), right.getOrElse("o")) 
    } 
    
    +0

    優秀な説明、ありがとう! – newf

    +0

    しかし、もう1つの質問:なぜ暗黙のオブジェクトIntVal'に '型A'を明示的に指定すべきですか? 'def key'定義から推定できますか? – newf

    +0

    おそらく、 'key'メソッドのパラメータ化されたバージョンを使うことができます:def key [A]:A' – incrop

    2

    構造型はJavaリフレクションで実装されているため、パフォーマンスが低下します。スクリプトのような短いプログラムや初期設定では問題ありませんが、集中的に使用するとプログラムが無意識になることがあります...

    最初に選択します。少なくとも2つの型パラメータが必要です。

    trait Tree[T,A] { 
        def key(): A 
        def union(x: T): T 
    } 
    
    +0

    彼は方法がT ' 'ではなく' Tree'上で定義されるように望んでいるようですね。 –

    3

    あなたは、単純な型にこれらのメソッドを「追加」することができるようにしたい場合は、多分あなたは使用したほうが良いと思います:あなたはより細かい粒度を必要としない場合しかし、あなたは、唯一の形質に行くことができますタイプクラス。 Read more about type classes in this questionと答えて、とappendの方法をIntStringに「追加する」方法を示すKevin Wrightの答えを見てください。

    関連する問題