У меня проблема с перерывами в коде Scala, где я работаю со значениями из неизменяемой карты со строковыми ключами. Вот базовый код, в том числе журнал отладки, я добавил:
val compStruct = subsq.comps get (ident)
compStruct match {
...
case None =>
logger.info(s"Found None, of type ${compStruct.getClass.getName}, at position $position (ident $ident)")
...
case x =>
logger.info(s"Illegal structure of type ${x.getClass.getName} at position $position (ident $ident) - x == None is ${x == None}, x.getClass == None.getClass is ${x.getClass == None.getClass}, x.getClass.getName == None.getClass.getName (${None.getClass.getName}) is ${x.getClass.getName == None.getClass.getName}")
...
}
проблема заключается в том, что случай x иногда принимается, когда значение фактически является None, как показано отлаживаемым результатом отладки:
INFO ...: Found None, of type scala.None$, at position 3000 (ident XX)
INFO ...: Illegal structure of type scala.None$ at position 3200 (ident XX) - x == None is false, x.getClass == None.getClass is true, x.getClass.getName == None.getClass.getName (scala.None$) is true
(Первая строка - это то, что я ожидаю, и это действительно произойдет нормально, остальное - случай ошибки)
Итак, если мне верить в ведение журнала (и я каким-то образом не испортил свое выражение), у меня есть случай, когда карта возвращает x, где x - это экземпляр класса scala.None $( тот же класс scala.None $, как видно из скомпилированного кода), но не соответствует случаю None и x == None is false.
Проблема с загрузкой классов будет очевидной причиной, но x.class== None.class, похоже, исключает это.
Добавлено: Как я предложил в комментариях, я могу воспроизвести экземпляры None, не соответствующие следующему коду:
object Test {
def main(args: Array[String]): Unit = {
val none1 = None
val clas = this.getClass.getClassLoader.loadClass("scala.None$")
val constr = clas.getDeclaredConstructors()(0)
constr.setAccessible(true)
val none2 = constr.newInstance()
println(s"none1 == none2 is ${none1 == none2}")
println(s"none1 == None is ${none1 == None}")
println(s"none2 == None is ${none2 == None}")
}
}
Что дает:
none1 == none2 is false
none1 == None is false
none2 == None is true
Я не думаю, что это имеет какое-либо отношение к тому, что происходит в приложении.
Добавлено: я изменил фактический файл класса $$, чтобы как печатать сообщение, когда конструктор выполняет, так и генерирует исключение, если значение None $.MODULE $не равно null при вызове конструктора и даже перемещает хранилище в статическое значение MODULE $для блока статического конструктора (исходный код имел это хранилище в конструкторе, что, по моему мнению, является технически нарушением правил JVM, поскольку объект не считается инициализированным до тех пор, пока не вернется конструктор).
Это блокирует вызов отражения конструктору (выше образца кода), который дублирует симптомы проблемы, но ничего не меняет в фактическом приложении. Значение None $.MODULE $изменяется от одного выполнения кода к другому, даже если класс остается тем же (тот же System.identityHashCode), но конструктор вызывается только один раз.