Scala对象初始化错误

时间:2016-09-19 09:39:54

标签: scala enumeration

我发现了&#34;手写枚举初始化的错误&#34;在斯卡拉。它是手写的,因为 constructor(private routeParams: RouteParams, private _ngZone:NgZone, private _el:ElementRef) { window.onresize = (e) => { this.getScreenWidth(); }; } ngOnInit() { this.getScreenWidth(); } private ordersEntityQuantity:number; private getScreenWidth() { this._ngZone.run(() => { this.width = window.innerWidth; }); switch(true) { case this.width < 1100 : this.ordersEntityQuantity = 1; break; case this.width < 1300 : this.ordersEntityQuantity = 2; break; case this.width < 1500 : this.ordersEntityQuantity = 3; break; case this.width >= 1500 : this.ordersEntityQuantity = 5; } this.lastOrdersEntity = this.firstOrdersEntity + this.ordersEntityQuantity; } sealed case class内部有对象。

有趣的是 - 如果object SomeCode有默认值 - 会发生一些黑暗魔法。 例如,我们有&#34;手写枚举&#34;看起来像是:

sealed case class

一次测试:

sealed case class SomeCode(
  id: String,
  legend: String)

object SomeCode {

  object First        extends SomeCode(id = "First", legend = "first legend")
  object Second        extends SomeCode(id = "Second", legend = "second legend")

  val values = Seq(
    SomeCode.First,
    SomeCode.Second)

  private val CACHE: Map[String, SomeCode] = {
    val ids = values.map(_.id)
    (ids zip values).toMap
  }

  def getById(id: String): Option[SomeCode] = CACHE.get(id)
}

当我们致电import com.blabla.SomeCode import org.scalatest.{Matchers, WordSpec} class SomeCodeTest extends WordSpec with Matchers { "SomeCode" should { "work properly" in { println(SomeCode.First.toString) } } } 时,SomeCode.Fist的初始化开始了。因此,object SomeCodeval values的初始化也会启动,实际上一切正常。

但是,如果我们为private val CACHE引入默认值...:

sealed case class

现在运行我们的测试 - 我们将在sealed case class SomeCode( id: String, legend: String = "default legend") ... object First extends SomeCode(id = "First") object Second extends SomeCode(id = "Second") 中使用NPE。

在测试中,我们调用CACHE - SomeCode.First中的此值为null,因此values会抛出NPE。 如果来自测试,我们会调用values.map(_.id),然后SomeCode.Second将在null

我知道扩展SomeCode.Second不是一个好习惯,但它应该正常工作。也许我不理解scala中的某些东西,但目前它看起来像是一个编译器错误。

sealed case class

我也在scala-lang中创建了问题:https://issues.scala-lang.org/browse/SI-9929

1 个答案:

答案 0 :(得分:2)

问题正在发生,因为当我们致电SomeCode.First.toString时,SomeCode.First在以下代码中最终为null

val values = Seq(SomeCode.First, SomeCode.Second)

您可以通过在REPL中打印值的输出来检查上述内容。

有趣的是,请使用以下代码查看REPL输出:

sealed case class SomeCode(
  id: String,
  legend: String = "default")

object SomeCode {
  println("begin object init")
  object First extends SomeCode(id = "First"){println("initializing First")}
  object Second extends SomeCode(id = "Second"){println("initializing Second")}
  println(SomeCode.First)
  println(SomeCode.Second)
}

SomeCode.First

// REPL Output:
begin object init
null  <--- SomeCode.First is null!!! Why does it not initialize the First object?
initializing Second  <--- Correctly initializes the Second object.
SomeCode(Second,default)
initializing First  <--- Now starts to initialize the First object
res41: SomeCode.First.type = SomeCode(First,default)