10


scala でコンパイラ エラーが発生しましたが、それが何を指しているのかわかりません。
次の宣言を想定します。

trait Abstract {
  type MyType
}
trait AInner
trait A extends Abstract{
  type MyType <: AInner
}
trait BInner {
  def bMethod : Int
}
trait B extends Abstract with A{
  override type MyType <: BInner with A#MyType
}
ここで ( trait で) 達成しようとしているのは、で宣言さBれた型をさらに制限することです。そのため、 type の値はmixin ツリー内のすべての を拡張する必要があります。MyTypeAbstractMyTypeMyType

コンパイラから次のメッセージが表示されます (タイトルのように): type MyType is a volatile type; 不揮発性の上限を持つ型をオーバーライドすることはできません。エラーの一部であるtype conjuction が原因で、ここで型の揮発性が発生していることを理解しています。 type with non-volatile upper boundおそらく型宣言を参照しています。 with A#MyTypetype MyType <: AInnerAInner

なぜ私はそれを行うことができないのですか?私の目標を達成する方法はありますか?

4

3 に答える 3

1

で書き直すことができtrait Bます(目標については後で詳しく説明しますが、これは少し異なると思います)

trait B extends A {
  type MyType <: BInner with AInner
}

そして、これは完全に理にかなっています。type の値は、 aまたは aB#MyTypeと見なすことができます。BInnerAInner

はすでに のサブクラスであるAbstractため、繰り返す必要はありません。これは型宣言に対して暗黙的であるため、記述する必要はありません。だから問題は、なぜとして機能しないのですか?AAbstractoverrideA#MyTypeAInner

これは、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 {
  }
}

さて、これがあなたが探しているものであることを願っています。

于 2013-04-20T22:18:45.010 に答える