次の階層を考慮してください。
class Foo
class Bar extends Foo { def bar = () }
class Baz extends Bar { def baz = () }
そしてあなたに似たクラス:
class Cov[+T](val item: T, val existing: List[T] = Nil) {
def append[S >: T](value: S) = new Cov[S](value, item :: existing)
}
Foo
次に、サブタイプごとに 3 つのインスタンスを作成できます。
val cFoo = new Cov(new Foo)
val cBar = new Cov(new Bar)
val cBaz = new Cov(new Baz)
bar
そして、要素を必要とするテスト関数:
def test(c: Cov[Bar]) = c.item.bar
それは保持します:
test(cFoo) // not possible (otherwise `bar` would produce a problem)
test(cBaz) // ok, since T covariant, Baz <: Bar --> Cov[Baz] <: Cov[Bar]; Baz has bar
append
メソッドは、上限に戻ります。
val cFoo2 = cBar.append(new Foo)
Foo >: Bar
, List[Foo] >: List[Bar]
, Cov[Foo] >: Cov[Bar]
. _
これで、正しくbar
アクセスできました:
cFoo2.item.bar // bar is not a member of Foo
上限が必要な理由を理解するために、次のことが可能だったと想像してください
class Cov[+T](val item: T, val existing: List[T] = Nil) {
def append(value: T) = new Cov[T](value, item :: existing)
}
class BarCov extends Cov[Bar](new Bar) {
override def append(value: Bar) = {
value.bar // !
super.append(value)
}
}
それからあなたは書くことができます
def test2[T](cov: Cov[T], elem: T): Cov[T] = cov.append(elem)
また、次の違法行為が許可されます。
test2[Foo](new BarCov, new Foo) // BarCov <: Cov[Foo]
でvalue.bar
呼び出される場所Foo
。(正しく) 上限を使用するとappend
、仮説上の最後の例のように実装することはできません。
class BarCov extends Cov[Bar](new Bar) {
override def append[S >: Bar](value: S) = {
value.bar // error: value bar is not a member of type parameter S
super.append(value)
}
}
したがって、型システムは健全なままです。