【问题标题】:How does the initialization of classes in Scala work?Scala 中类的初始化是如何工作的?
【发布时间】:2020-09-09 20:23:21
【问题描述】:

下面的代码抛出一个java.lang.NullPointerException,因为这个特征被过早地初始化了。

trait DummyTrait {
  def intSeq: Seq[Int]
  require(intSeq.exists(_ > 2))
}
object Dummy extends DummyTrait {
  val extraIntSeq: Seq[Int] = Seq(-2,-3)
  override def intSeq = Seq(1,0,4) ++ extraIntSeq
}

Dummy.intSeq

但是,下面的简单更改解决了这个问题,但我不明白为什么。

trait DummyTrait {
  def intSeq: Seq[Int]
  require(intSeq.exists(_ > 2))
}
object Dummy extends DummyTrait {
  lazy val extraIntSeq: Seq[Int] = Seq(-2,-3) // using `def` also works
  override def intSeq = Seq(1,0,4) ++ extraIntSeq
}

Dummy.intSeq

我找到了this documentation about overriden val being NULL,但它似乎不适用于上面的示例,因为修复不涉及在超类的接口中定义的变量。

另外,上面提出的解决方案是反模式吗?作为开发 trait 的人,我应该如何强制要求抽象值,而不会让实现具有潜在 NullPointerException 的子类的用户感到惊讶?

Obs.:我使用的是 Scala 版本 2.13.0

【问题讨论】:

  • 我宁愿使用精炼类型或智能构造函数,但无论如何这个问题很有趣。

标签: scala initialization traits initializer anti-patterns


【解决方案1】:

在第一种情况下,extraIntSeq 在构造函数中初始化 超级构造函数被调用,因此 NPE

  object Dummy extends DummyTrait {
    private[this] val extraIntSeq: Seq = _;
    ...
    def <init>($outer: O): Dummy.type = {
      Dummy.super.<init>();
      Dummy.this.extraIntSeq = ... // note that it comes AFTER super
      ()
    }
  }

而在后者中,懒惰的 val 变成了方法。

【讨论】:

【解决方案2】:

到目前为止,您可以使用早期初始化程序

object Dummy extends {
  val extraIntSeq: Seq[Int] = Seq(-2,-3)
  override val intSeq = Seq(1,0,4) ++ extraIntSeq
} with DummyTrait

In Scala, what is an "early initializer"?

https://dotty.epfl.ch/docs/reference/dropped-features/early-initializers.html

https://contributors.scala-lang.org/t/proposal-to-remove-early-initializers-from-the-language/2144

https://github.com/scala/scala-dev/issues/513

【讨论】:

  • hmmm,很有趣,但我认为它与lazy val 解决方案相似,因为它仍然让谁负责实现子类。
  • @PedroIgorA.Oliveira 好吧,在 Dotty 中,特征参数代替了早期的初始化器 scastie.scala-lang.org/q8wSND9CRkWTqcs0xTLgFA 所以实现子类的人必须提供构造函数参数。
  • 很好,好多了!我想我将不得不等待 scala 3.0。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2023-03-07
  • 2020-08-22
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2012-09-23
相关资源
最近更新 更多