0

おそらく Scala の達人にとっては簡単なことでしょう。少し予期しない動作が見られるため、型のバインドされた制約について調べて、何かが足りないのではないかと考えています。このような階層に 3 つの型 A、B、C があり、型の境界を試しているとします。

class A {
}

class B extends A {
}

class C extends B {
}

class MyList1 { // T super B
  def add[T >: B](a: T): Unit = {}
}

class MyList2 { // T extends B
  def add[T <: B](a: T): Unit = {}
}

class MyList3[T >: B] { // T super B
  def add(a: T): Unit = {}
}

class MyList4[T <: B] { // T extends B
  def add(a: T): Unit = {}
}

object BoundsClass {

  def main(args: Array[String]) {
    val l1 = new MyList1
    l1.add(new A) 
    l1.add(new B)
    l1.add(new C) // why is this allowed??

    val l2 = new MyList2
    // l2.add(new A) // not allowed (OK)
    l2.add(new B)
    l2.add(new C)

    val l3a = new MyList3[A]
    val l3b = new MyList3[B]
    // val l3c = new MyList3[C] // not allowed (OK)

    // val l4a = new MyList4[A] // not allowed (OK)
    val l4b = new MyList4[B]
    val l4c = new MyList4[C]
  }

}

コレクションは、1 つのケースを除いてすべて期待どおりに動作しています。l1.add(new C); を参照してください。コンパイルエラーを引き起こしません。なぜこれが許可されているのですか?

ありがとう!

4

2 に答える 2

3

私はスカラの第一人者であると主張しているわけではありませんが、これを突き刺します。

の行に沿って型階層を定義したA >: B >: Cので、次のようなことができます

val aa: A = new A
val ab: A = new B
val ac: A = new C

val bb: B = new B
val bc: B = new C

val cc: C = new C

あなたが言うことができるようにval a: Any = new Whatever

new Cしたがって、 toを追加しようとするとl1、インスタンスのように扱われBます。これは、メソッドの型の境界に準拠する、それ自体の最も近い利用可能なバージョンであるためです。

于 2012-12-23T14:42:21.987 に答える
0

そのように使用する場合、下限は役に立ちません。Liskov置換原則によれば、クラスのインスタンスが必要な場所であればどこでもサブクラスのインスタンスを使用できる必要があるため、値パラメーターに下限を強制することはできません。new Cしたがって、のインスタンスと見なすことができるため、コードはコンパイルされますB

一般に、その理由から、メソッドの値パラメーターに下限を設定することは役に立ちません。下限は、クラスの型パラメーターをバインドする2番目のケースで間違いなくより便利です。すべての型パラメーターはコンパイル型で解決されるため、2番目のケースではコンパイラーがコンパイラー・エラーを生成することが予想されます。下限の使用法のより具体的な例は、ここにあります

于 2012-12-23T22:50:16.850 に答える