意外的Scala默认值行为

时间:2009-12-05 20:43:07

标签: scala default-value

为什么此处的默认值在明确指定给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

1 个答案:

答案 0 :(得分:4)

我很确定这与基元的装箱/拆箱有关。如果编写通用代码来处理基元,则必须将基元打包,然后在将其用作基元的位置将其取消装箱。我不确定使用什么拆箱算法,但我想它是按照以下几行:

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

因此,非常奇怪的是我可能会添加,简单包装类中字段t的默认值始终为null,因为字段始终为将成为一个盒装原语,因为泛型是通过类型擦除在JVM级别实现的。因此,所有JVM都看到t的类型为Object,值为null。因此,方法get将始终返回null,但是当泛型方法get应返回基本类型时,null将取消装箱为默认值。

此外,用反射进行一些探测确实表明该字段确实是null

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

null的乐趣。这个问题的一个解决方案是使用2.8 @specialised注释,如果已经在你使用的每晚构建中实现的话。

或者,更好的是,Scala编译器可以将这些字段默认为所用基元的实际默认值的盒装默认值。例如,对于SimpleWrap[Boolean]t在运行时将具有类型Object和值java.lang.Boolean(false)

编辑:错误报告submitted

另一个奇怪的事情:

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

为了使泛型真正具有通用性并且具有一致的行为,这是应该解决的问题!目前,您的get方法没有一致的行为。

- Flaviu Cipcigan