スカラーの「手書き列挙」の初期化でバグが見つかりました。オブジェクトが内部にあるのはsealed case class
とobject SomeCode
なので手書きです。Scalaオブジェクト初期化のバグ
おもしろいことに、sealed case class
にデフォルト値が設定されていると、多少の暗い魔法が発生します。我々はobject SomeCode
開始の初期化SomeCode.Fist
を呼び出すと
import com.blabla.SomeCode
import org.scalatest.{Matchers, WordSpec}
class SomeCodeTest extends WordSpec with Matchers {
"SomeCode" should {
"work properly" in {
println(SomeCode.First.toString)
}
}
}
:
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)
}
そして、もう一つのテスト: は、たとえば、我々は次のようになり、 "手書きの列挙" を持っています。したがって、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")
、今我々のテストを実行します - 私たちはCACHE
でNPEを持つことになります。
SomeCode.First
- この値はnull
となり、values
になるので、values.map(_.id)
はNPEを投げます。 テストから、我々はSomeCode.Second
を呼び出します場合は、null
は、私はそれががsealed case class
拡張良い習慣ではないことを知っているが、それにもかかわらず、それが正常に動作するはずSomeCode.Second
になります。たぶん私はスカラーで何かを理解していないかもしれませんが、現在は私にとってはコンパイラのバグのようです。
scalaVersion := "2.11.7"
また、私はScalaの-LANGで問題を作成します。私たちはSomeCode.First.toString
を呼び出すときに、SomeCode.First
次のコードでnull
としてセットアップ済みですのでhttps://issues.scala-lang.org/browse/SI-9929
:
興味深いことに、次のコードでREPLの出力を見て?なぜなら、与えられたコードでは、あなたが記述した振る舞いを再現することができないからです。言い換えれば: 'Works fine for me' –
@SaschaKolbergは、デフォルト値である 'legend:String =" default legend ")でうまく動作し、拡張オブジェクトでこの値を設定しません。 – invis
いいえ、そうではありません。 –