タイプに関して「オーバーライド」について話すのではなく、その範囲を狭めることについて話します。
type T
...限界はありません
type T <: C
...T
はC
またはのサブタイプC
(これは上界と呼ばれます)
type T >: C
...T
はC
またはのスーパータイプ(下限C
と呼ばれます)
type T = C
...T
正確にC
(タイプエイリアス)
したがって、T
が特性のタイプメンバーでA
ありSubA
、のサブタイプであるA
場合、(2)のSubA
場合T
はより特定のサブタイプC
に絞り込むことができますが、(3)の場合はより高いスーパータイプのに絞り込むことができC
ます。ケース(1)は、に制限を課しませんがSubA
、ケース(4)は、T
いわば「最終」であることを意味します。
これは、メソッドの引数の型として表示されるか、メソッドの戻り型として表示されるかにかかわらず、 T
inの使いやすさに影響を及ぼします。A
例:
trait C { def foo = () }
trait SubC extends C { def bar = () }
trait MayNarrow1 {
type T <: C // allows contravariant positions in MayNarrow1
def m(t: T): Unit = t.foo // ...like this
}
object Narrowed1 extends MayNarrow1 {
type T = SubC
}
object Narrowed2 extends MayNarrow1 {
type T = SubC
override def m(t: T): Unit = t.bar
}
タイプは(メソッド引数のタイプとして)反変の位置で発生するm
ためMayNarrow1
、メソッドを定義することができます。したがって、のサブタイプで絞り込まれた場合でも有効です(メソッド本体はタイプであるかのように扱うことができます)。T
T
MayNarrow1
t
C
対照的に、type T = C
必然的に修正されますT
。これは、メソッドの作成に対応しfinal
ます。を固定することにより、共変位置で(メソッドの戻り型として)T
使用できます。
trait Fixed extends MayNarrow1 {
type T = C // make that T <: C to see that it won't compile
final def test: T = new C {}
}
これで、さらに「オーバーライド」することを禁止する必要があることが簡単にわかりますT
。
trait Impossible extends Fixed {
override type T = SubC
test.bar // oops...
}
完全を期すために、これは下限のあまり一般的ではないケースです。
trait MayNarrow2 {
type T >: SubC // allows covariant positions in MayNarrow2
def test: T = new SubC {}
}
object Narrowed3 extends MayNarrow2 {
type T = C
test.foo
}
object Narrowed4 extends MayNarrow2 {
type T = C
override def test: T = new C {}
}