【问题标题】:scala: why does underscore (_) initialization work for fields but not method variables?scala:为什么下划线(_)初始化适用于字段而不适用于方法变量?
【发布时间】:2016-04-30 21:29:38
【问题描述】:

这行得通:

scala> class foo[T] {
     | var t: T = _
     | }
defined class foo

但这不是:

scala> def foo[T] = {
     |   var t: T = _
     | }
<console>:5: error: local variables must be initialized
         var t: T = _

为什么?

(可以使用:

var t: T = null.asInstanceOf[T]

)

【问题讨论】:

    标签: scala


    【解决方案1】:

    Martin 的回答是 a mailing list thread

    对应JVM。您可以省略字段初始化,但不能省略局部变量初始化。省略局部变量初始化意味着编译器必须能够为每种类型合成一个默认值。面对类型参数、专业化等,这并不容易。

    当被问及在 Scala 合成默认值的问题上,字段和本地变量之间存在或应该有什么区别时,他接着说:

    在字节码方面存在明显差异。默认情况下,JVM 会初始化对象字段,并要求显式初始化局部变量。 [...] 我不确定我们是否应该打破 Java 的一个有用原则(本地变量在使用之前必须被初始化),或者我们是否应该像在 Java 中那样深入研究并引入基于流的初始化检查。这将是更好的解决方案,IMO,但在规范和实施方面需要大量工作。面对这些选择,我的本能是现在什么都不做:-)

    所以如果我理解正确的话,Scala 编译器实际上并没有合成对象字段的默认值,它生成的字节码让 JVM 来处理。

    根据SI-4437,Martin 同意在语言规范中实际支持null.asInstanceOf[T] 模式,这似乎是因为无法在现有约束下切实支持更好的替代方案。

    【讨论】:

      【解决方案2】:

      这在Scala Language Specification(我的斜体字)的4.2部分中定义

      变量定义var x: T = _ 只能作为模板的成员出现。它 引入了一个类型为T 和一个默认初始值的可变字段

      当然,这并不能回答为什么会这样!

      【讨论】:

      • 我知道这是一个非常古老的答案,但链接已失效:(
      【解决方案3】:

      这是我刚刚发现的至少一个用例。当超类通过反射初始化成员变量时,它实际上可以初始化子类的成员变量。但是,如果子类也用一个值初始化成员变量,那么这将具有覆盖超类给它的值的效果。这可以通过使用下划线初始化子类成员变量来避免。这就是为什么语言规范谈到为变量提供一个 getter 函数,该函数返回的当前值比 oxbow_lake 的句子中引用的句子稍远。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2015-11-12
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2019-03-06
        • 2012-12-23
        相关资源
        最近更新 更多