Я нашел ошибку при инициализации «рукописного перечисления» в scala. Это рукописный, потому что это sealed case class
и object SomeCode
, у которых есть объекты внутри.Ошибка инициализации объекта Scala
Что интересно - если 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
- и это значение будет в values
null
, так values.map(_.id)
выбросит NPE. Если из тестов мы будем называть SomeCode.Second
тогда null
будет SomeCode.Second
Я знаю, что это не очень хорошая практика распространяется sealed case class
, но тем не менее он должен работать правильно. Возможно, я не понимаю что-то в scala, но в настоящее время это похоже на ошибку компилятора для меня.
scalaVersion := "2.11.7"
Также я создаю проблемы в Ла Скала-лана: https://issues.scala-lang.org/browse/SI-9929
Может быть, что-то не хватает в ваших примерах кода? Потому что, с указанным кодом, я не могу воспроизвести описанное вами поведение. Другими словами: «Хорошо работает для меня» –
@SaschaKolberg отлично работает для вас со значением по умолчанию - 'legend: String =" default legend ")' и не устанавливает это значение в расширенных объектах – invis
нет, это не так. –