【问题标题】:Unexpected Scala default values behavior意外的 Scala 默认值行为
【发布时间】:2010-12-23 15:05:33
【问题描述】:

为什么这里的默认值在显式分配给 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

【问题讨论】:

    标签: scala default-value


    【解决方案1】:

    我很确定这与原语的装箱/拆箱有关。如果您编写通用代码来处理原语,则必须将原语装箱,然后在您将其用作原语的地方将其拆箱。我不确定使用的是什么拆箱算法,但我想它是以下几行:

    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) 
      }
    

    哦,nulls 的乐趣。此问题的一种解决方案是使用 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 方法没有一致的行为。

    -- 弗拉维乌·西普西根

    【讨论】:

    • 不客气 :)。这绝对是一个有趣的问题。
    猜你喜欢
    • 2014-03-22
    • 2017-05-24
    • 2014-10-03
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-01-31
    • 2014-06-25
    相关资源
    最近更新 更多