2

Scala 2.10.3 で値クラス (AnyVal を拡張するクラス) をいじっていますが、それらを抽象メソッドのパラメーターとして使用すると、奇妙なコンパイラ エラーが発生します。次の例が示すように:

class ValueClass(val x: Int) extends AnyVal

trait Test {
  def foo(v: ValueClass): Int
}

new Test {
  override def foo(v: ValueClass): Int = 1
}

コンパイラは次のエラーを吐き出します。

error: bridge generated for member method foo: (v: ValueClass)Int in anonymous class $anon
which overrides method foo: (v: ValueClass)Int in trait Test
clashes with definition of the member itself;
both have erased type (v: Int)Int
          override def foo(v: ValueClass): Int = 1

なぜこれが機能しないのですか?値クラスを抽象メソッドに渡す方法はありますか?

4

1 に答える 1

2

他の人が指摘したように、この問題は後のバージョンで修正されています。何が変更されたのか知りたい場合は、このプル リクエストを参照することをお勧めします。

SI-6260 値クラスに対するラムダによる double-def エラーの回避 消去されたシグネチャがオーバーライドされたメソッドからのジェネリック シグネチャと重複する場合、基になる型へのメソッド シグネチャの値クラスの事後消去は大混乱を引き起こします。両方の余地はありません。しかし、実際には両方が必要です。インターフェイス メソッドの呼び出し元は、ブリッジがボックス化を解除する必要があるボックス化された値を渡し、ボックス化されていない値を受け入れる特定のメソッドに渡します。

これは、ほとんどの場合、無名関数のパラメーターまたは戻り値の型として使用される Object に消去される値クラスで発生します。

サブクラスのボックス化されていない特定のメソッドに別の名前を選択しない限り、これは扱いにくいと考えられていました。しかし、それは呼び出しサイトの書き換えや特殊化を必要とする大きな作業のように思えます。

しかし、呼び出しサイトを書き直す必要がない重要な特殊なケースがあります。メソッドを定義するクラスが匿名の場合、ボックス化されていないメソッドは実際には必要ありません。ジェネリック メソッドを介してのみ呼び出されます

Java 8 ラムダがどのように処理されるかを見て、私はこの認識に達しました。ブリッジメソッドを期待していましたが、何も見つかりませんでした。ラムダ本体は、ジェネリック シグネチャと正確に一致するメソッドに直接配置されます。

このコミットは、ブリッジとターゲットの間の衝突を検出し、ターゲット メソッドのシンボルの名前を変更することによって匿名クラスを回復します。これはバイトコード名として使用されます。以前と同様に、必要なボックス化/ボックス化解除操作を使用して、それに汎用ブリッジを転送します。

于 2014-07-23T14:17:01.563 に答える