为什么(为了什么目的)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
。
我偶然发现了这个问题,它导致我目前正在编写的 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
。