为什么(为了什么目的)Scala 会自动初始化未初始化(有意)的变量?

Why (and to what purpose) does Scala automatically initialize variables that are unintialized (itentionally)?

我偶然发现了这个问题,它导致我目前正在编写的 OpenGL 应用程序出现问题,所以我不得不问:

abstract class Entity
{
  protected var modelMatrixLocation: Int = _
  protected var modelViewProjectionMatrixLocation: Int = _
}

class ConcreteEntity extends Entity
{
  modelMatrixLcoation: Int = getUniformLocation(shaderID, "modelMatrix")

  println(modelMatrixLocation)
  println(modelViewProjectionMatrixLocation)
}

具体实体打印出来

0

0

现在显然现实世界的例子有点复杂,但这正是发生的事情。我有两个 Int 表示着色器中制服的位置,但忘了初始化一个。

然后我不得不进行大量调试以找出为什么我的着色器表现如此奇怪(在它工作之前 - 这纯粹是巧合,因为从未使用过 modelMatrix 但设置了 modelViewProjectionMatrix,所以这一切奇迹般地起作用了)

所以我的问题是: 1.) 为什么未初始化的变量 Int 设置为 0? (而不是,例如,-1)我的意思是,-1 会更合适,因为它不会与 SQL-queries、Collection-object-fetching 或类似的东西发生冲突——在计算机科学中我们通常开始用 0 计数,所以 -1 会给我们带来更明显的错误。

2.) 我怎样才能避免这种情况?我如何确定 abstract class Entity 中的所有变量都已填满?

我的意思是,我可能会做类似的事情:

protected var modelMatrixLocationName: String = _
protected val modelMatrixLocation: Int = getUniformLocation(shaderID, "modelMatrixLocationName")

稍微调整了一下,但还是很丑。

另一种方法是使用 Option。一方面,这似乎是一种很好的处理方式,但我仍然需要使用 var,我想避免这种情况。 val一路走好! ;)

有更好的主意吗?

您实际上是通过 _ 初始化它们,因为您将 anything 分配给它们。

要解决您的问题,您可以不为这些变量分配任何内容(您是抽象的 class,因此您应该能够做到这一点)或使用 traits,即 Java 的接口,但它们可以包含或函数体。在您的示例中,关于特征的更有趣的事实是,它们可以包含未初始化的字段。

为什么一个未初始化的变量Int设置为0

正如李所说:变量没有被初始化。它用 _.

初始化

所以这是 0 的原因: 编译到 JVM 后,所有值都有一个初始值,由 JVM 定义。 因此,例如,对于整数,它是 0,对于大多数其他 类,它是 null。 如果您使用 ScalaJS,则默认值将是 JavaScript.

定义的值

我怎样才能避免这种情况?

使用 trait

trait Entity {
  def  modelMatrixLocation: Int
  def modelViewProjectionMatrixLocation: Int
}

真正的原因是 JVM 需要先擦除内存区域,然后再将它们交给新创建的对象,并且用零填充内存是可以非常快速地完成的事情。它也很好地与 null 的表示形式相吻合。这与Scala无关,因此也无法避免。

因此,如果您希望变量以已知的错误状态开始,请在程序中将 _ 替换为 -1