3

ここでのデフォルト値は、valに明示的に割り当てられた場合と、直接印刷された場合とで動作が異なるのはなぜですか?

package blevins.example

class SimpleWrap[T] {
  var t: T = _
  def get = t
}

object App extends Application {
  val swb = new SimpleWrap[Boolean]
  val b = swb.get
  println("b: " + b)  // b: false
  println("swb.get: " + swb.get) // swb.get: null

  val swi = new SimpleWrap[Int]
  val i = swi.get
  println("i: " + i) // i: 0
  println("swi.get: " + swi.get) // swi.get: null
}

私は2.8r19890を使用しています。


編集-「get」がAnyを期待して呼び出されたときに奇妙なことが起こるようです。

  val any1: Any = swb.get
  val any2: Any = b
  println("any1: " + any1) // any1: null
  println("any2: " + any2) // any2: false
4

1 に答える 1

4

これは、プリミティブのボックス化/ボックス化解除と関係があると確信しています。プリミティブで動作するジェネリックコードを作成する場合は、プリミティブをボックス化してから、プリミティブとして使用した場所でボックス化を解除する必要があります。どの開開アルゴリズムが使用されているかはわかりませんが、次のようになっていると思います。

if(box == null) 
  default value
else
  box.unbox

したがって、非常に奇妙なことに、ジェネリックは型消去によってJVMレベルで実装されるため、フィールドは常にボックス化されたプリミティブになるため、t単純なラッパークラスのフィールドのデフォルト値は常にになります。nullしたがって、JVMが認識するのは、値が。tのタイプのすべてです。したがって、メソッドは常にを返しますが、ジェネリックメソッドがプリミティブ型を返すことになっている場合、はデフォルト値にボックス化されません。Objectnullgetnullgetnull

また、反射を少し覗いてみると、実際にフィールドが実際にあることがわかりnullます。

val sw = new SimpleWrap[Boolean]
sw.getClass.getDeclaredFields.map {
  f => f.setAccessible(true)
  f.get(sw) 
  }

ああ、sの楽しみnull。この問題の解決策の1つは、使用@specialisedするナイトリービルドに2.8アノテーションが実装されている場合、それを使用することです。

または、さらに良いことに、Scalaコンパイラーは、これらのフィールドを、使用されるプリミティブの実際のデフォルトのボックス化されたデフォルトにデフォルト設定することができます。たとえば、の場合、SimpleWrap[Boolean]実行時tにタイプObjectと値があります。java.lang.Boolean(false)

編集:提出されたバグレポート。

別の奇妙なこと:

val x: Int = null.asInstanceOf[Int] // 0
val y: Boolean = null.asInstanceOf[Boolean] // false

これは、ジェネリックが実際にジェネリックであり、一貫した動作をするために解決する必要があるものです。現時点では、getメソッドの動作に一貫性がありません。

--Flaviu Cipcigan

于 2009-12-05T23:23:42.357 に答える