我发现了"手写枚举初始化的错误"在斯卡拉。它是手写的,因为 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 SomeCode
和val 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
答案 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)