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