【问题标题】:Why (and to what purpose) does Scala automatically initialize variables that are unintialized (itentionally)?为什么(以及出于什么目的)Scala 会自动初始化(有意地)未初始化的变量?
【发布时间】:2015-09-19 08:58:00
【问题描述】:

我偶然发现了这一点,它在我目前正在编写的 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

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

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

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

2.) 我怎样才能避免这种情况?我如何确保 abstract class Entity 中的所有变量都被真正填充?

我的意思是,我可能会这样做:

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

稍作调整,但这很丑。

另一种方法是改用Option。一方面,这似乎是一种很好的(r)方式来处理这个问题,但我仍然需要使用一个 var,我想避免这种情况。一路vals! ;)

有更好的想法吗?

【问题讨论】:

  • _ 不会留下未初始化的变量,它会显式地将它们初始化为默认值,对于Int,它是 0。
  • 但是在Scala中没有办法只declare一个变量,是吗?

标签: scala variables initialization var


【解决方案1】:

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

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

【讨论】:

  • lazy 不允许与 var 一起使用。那么惰性评估究竟如何帮助解决我的问题呢?
  • @Teolha Sry 我误解了问题
  • 非常感谢。好吧,这里不能选择特征,因为实体确实包含一些我在问题中省略的构造函数参数。当然我可以为制服添加另一个特征,但因为它们或多或少属于实体......我会看到:)
  • scala> null.asInstanceOf[Int] res0: Int = 0 请参阅规范,第 6.3 节 scala-lang.org/files/archive/spec/2.11/…
【解决方案2】:

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

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

【讨论】:

    【解决方案3】:

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

    正如 Lee 所说:该变量没有被统一化。初始化为_

    所以这里为什么它是 0: 编译到 JVM 的所有值都有一个初始值,由 JVM 定义。 例如,对于整数来说,它是0,对于大多数其他类来说,它是null。 如果您使用 ScalaJS,默认值将是 JavaScript 定义的值。

    如何避免这种情况?

    使用trait

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

    【讨论】:

    • 遗憾的是,这里不能选择 trait,因为它不允许构造函数参数,我省略了,但在实际应用程序中存在。我只是想知道为什么 0 是默认值......但我认为这是因为它是加法的标识元素......或者只是自然数从那里开始。
    猜你喜欢
    • 2016-05-11
    • 2011-12-09
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2022-09-27
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多