根据抽象val的成员定义val(Scala bug?)

根据抽象val的成员定义val(Scala bug?),scala,Scala,我遇到一个运行时错误,想知道这是Scala中的一个bug,还是至少不应该在编译时捕获它。 此代码生成NullPointerException: object Main extends App { trait A { val data: { val x: Int } val x = data.x } val a = new A { val data = new Object { val x = 42 } } a.x } 当然,通过使A.x变懒或Adef

我遇到一个运行时错误,想知道这是Scala中的一个bug,还是至少不应该在编译时捕获它。 此代码生成NullPointerException:

object Main extends App {
  trait A {
    val data: { val x: Int }
    val x = data.x
  }
  val a = new A {
    val data = new Object { val x = 42 }
  }
  a.x
}

当然,通过使A.x变懒或A
def
来修复这一问题很容易,但在这个最小的示例中,这一点很明显,但在更现实的代码中,它可能有点令人困惑。

当您第一次遇到它时,这会让人困惑,但这是预期的行为

通常的初始化顺序是先初始化super traits中的VAL。在您的示例中,这意味着trait A中的
val x
在匿名子类中的
val data
之前被初始化,因此导致空指针

如果你想让你的例子发挥作用,你必须使用一个叫做“早期定义”的特性(语言规范中的5.1.6)

在您的具体示例中,这是您需要使用的语法:

val a = new {
  val data = new Object { val x = 42 }
} with A  

这将在初始化A中的val之前初始化数据val。

我忘记了在一个问题FAQ中提到了此选项

$ scala -Xcheckinit
Welcome to Scala version 2.11.0-RC1 (OpenJDK 64-Bit Server VM, Java 1.7.0_25).
Type in expressions to have them evaluated.
Type :help for more information.

scala> object Main extends App {
     |   trait A {
     |     val data: { val x: Int }
     |     val x = data.x
     |   }
     |   val a = new A {
     |     val data = new Object { val x = 42 }
     |   }
     |   a.x
     | }
<console>:15: warning: a pure expression does nothing in statement position; you may be omitting necessary parentheses
         a.x
           ^
warning: there were 1 feature warning(s); re-run with -feature for details
defined object Main

scala> Main main null
scala.UninitializedFieldError: Uninitialized field: <console>: 13
  at Main$$anon$1.data(<console>:13)
  at Main$A$class.$init$(<console>:10)
  ... 43 elided
$scala-Xcheckinit
欢迎使用Scala版本2.11.0-RC1(OpenJDK 64位服务器虚拟机,Java 1.7.025)。
键入要计算的表达式。
键入:有关详细信息的帮助。
scala>object Main扩展应用程序{
|特征A{
|val数据:{val x:Int}
|val x=data.x
|   }
|val a=新a{
|val数据=新对象{val x=42}
|   }
|a.x
| }
:15:警告:纯表达式在语句位置不起任何作用;您可能省略了必要的括号
a、 x
^
警告:有1个功能警告;有关详细信息,请使用-功能重新运行
定义对象主
scala>Main空值
scala.UninitializedFileError:未初始化字段::13
在主$$anon$1处。数据(:13)
在主$A$类中。$init$(:10)
... 43删去

val data:{val x:Int}在Scala中是什么意思?这一定是重复的,因为答案总是一样的:@yannbane只是有一个成员x的东西。@som snytt你能详细说明一下吗?这并不能真正帮助我知道它是什么,只是它的行为。这是某种形式的模式匹配吗?如果有人有一个更权威的答案,那就太好了。@yannbane这个词是“结构类型”。事实上,“有成员x的东西”既不能告诉你它是什么,也不能告诉你它的行为,只能告诉你它的结构。规范中的3.2.7说,如果细化不是覆盖,那么它是结构化的。根据定义,此示例为
AnyRef{val x:Int}
。值得注意的是,根据注释中的常见问题,还有其他选项,最好的更改是,根据常见问题,在traits或lazy vals中使用defs。FTR,所以应该用评论和其他修正通知选民:你认为这是一个完整的答案,但这里有更多的信息给你。我完全同意,我的回答有点狭隘。对一个已经被接受的答案进行显著改进是否是一种普遍做法?我当然不介意这样做。