で書き直すことができtrait B
ます(目標については後で詳しく説明しますが、これは少し異なると思います)
trait B extends A {
type MyType <: BInner with AInner
}
そして、これは完全に理にかなっています。type の値は、 aまたは aB#MyType
と見なすことができます。BInner
AInner
はすでに のサブクラスであるAbstract
ため、繰り返す必要はありません。これは型宣言に対して暗黙的であるため、記述する必要はありません。だから問題は、なぜとして機能しないのですか?A
Abstract
override
A#MyType
AInner
これは、scala 言語仕様が揮発性型について述べていることです。
3.6 揮発性型
型の揮発性は、型パラメーターまたは型の抽象型インスタンスが null 以外の値を持たない可能性を概算します。(§3.1) で説明したように、volatile 型の値メンバーはパスに出現できません。次の 2 つの条件のいずれかが満たされる場合、型は volatile です。1. T2、...、Tn の 1 つが型パラメーターまたは抽象型である、または 2. T1 が抽象型であり、j > 1 の詳細化 R または型 Tj のいずれかが複合型の抽象メンバーに寄与する、または 3. T1、...、Tn のいずれかがシングルトン型です。ここで、 S に T のメンバーでもある抽象メンバーが含まれている場合、型 S は型 T に抽象メンバーを提供します。T のメンバーでもある抽象宣言が R に含まれている場合、リファインメント R は型 T に抽象メンバーを提供します。型指定子は、それが volatile 型のエイリアスである場合、または volatile 型を上限として持つ型パラメーターまたは抽象型を指定する場合、volatile です。パス p の基になる型が volatile の場合、シングルトン型 p.type は volatile です。T が volatile の場合、存在型 T forSome {Q } は volatile です。
仕様で言及されているその他の重要な項目は、抽象型のオーバーライドに関するものです。
抽象型メンバーには別の制限が適用されます。上限として揮発性型 (§3.6) を持つ抽象型メンバーは、揮発性上限を持たない抽象型メンバーをオーバーライドできません。
コンパイラ エラーは次のとおりです。
error: overriding type MyType in trait A with bounds <: AInner;
type MyType is a volatile type; cannot override a type with non-volatile upper bound
これは仕様と一致しています。BInner with A#MyType
揮発性です。その前に、MyType
不揮発性 as がありましAny
た。
問題は、scala 型システムの型は一意の意味を持たなければならないということです。抽象型は、宣言がサブクラスに委譲される型と考えることができます。したがって、抽象型がまだ抽象である場合、抽象型の値を宣言しても問題はありません。一方、 のようなBInner with A#MyType
型がある場合、この型にはいくつかの意味があります。MyType
これは volatile と呼ばれ、抽象型をインスタンス化するサブクラスと同じ数の型を持つことができるため、この型の非 null 値を持つことは意味がありません。Any
簡単にするために、 volatile 型は、 のサブタイプではない型(および volatile はサブタイプである)と考えることができますAny
。したがって、コンパイラーが言及する矛盾があります。
あなたが述べたあなたの目標に戻ります
ここで (特性 B で) 達成しようとしているのは、Abstract で > 宣言された MyType 型をさらに制限することです。
このような内部特性のおかげで、これを達成できます。
trait Abstract {
type MyType
}
trait B extends Abstract {
trait MyType {
def bMethod : Int
}
}
trait A extends B {
trait MyType extends super.MyType {
}
}
さて、これがあなたが探しているものであることを願っています。