Некоторый конструктор с asInstanceOf - PullRequest
4 голосов
/ 03 августа 2011

Когда я писал свой недавний ответ , я также пытался решить проблему более «функциональным» способом, но столкнулся со следующей проблемой:

<code>scala> "1".asInstanceOf[Int]
java.lang.ClassCastException: java.lang.String cannot be cast to java.lang.Integer
    at scala.runtime.BoxesRunTime.unboxToInt(Unknown Source)
        ...
но
<code>scala> Some("1".asInstanceOf[Int])
res29: Some[Int] = Some(1)
и только
<code>scala> res29.get
java.lang.ClassCastException: java.lang.String cannot be cast to java.lang.Integer
    at scala.runtime.BoxesRunTime.unboxToInt(Unknown Source)
        ...

Похоже, что аргумент Some оценивается лениво, но я не могу найти никакой подсказки в источниках . Параметр x в конструкторе Some является строгим.

Почему некоторые вместе с asInstanceOf ведут себя так странно?

1 Ответ

2 голосов
/ 03 августа 2011

Аргумент конструктора не лениво вычисляется. Момент, когда вы получаете ошибку, является моментом, когда REPL пытается отобразить результат в виде Int (unboxToInt). Если вы посмотрите дальше в стеке, вы найдете scala_repl_result.

Я считаю, что проблема в том, что asInstanceOf[Int] вообще не проверяет во время выполнения. Я не знаю, является ли это согласно спецификации (для типов значений) или ошибка. Компилятор обманом принимает, что "1" является Int (или в штучной упаковке Int), в ожидании проверки во время выполнения, подразумеваемой asInstanceOf, но этого не произойдет.

Поскольку Option / Some не являются специализированными, во время выполнения присутствует только Some[Object]. Таким образом, для JVM существует вызов конструктора new Some (Object o), который принимается при проверке кода и во время выполнения. toString (вызываемый REPL для недавно созданного Some) находится внутри общего кода, где T также обрабатывается как Object (или AnyRef), поэтому он работает, и отображается Some(1). С другой стороны, каждый раз, когда есть доступ к значению в контексте, когда компилятор знает тип универсального параметра, в код вставляется приведение (+ распаковка в случае типа значения). Это когда происходит сбой (здесь REPL выполняет распаковку перед отображением).

Редактировать Это было в Scala 2.8.1. Согласно комментарию @incrop выше, это сейчас исправлено.

...