Почему Scala иногда прибегает к Java-объектам?
Я почти уверен, что этот вопрос задавался раньше, но мне не хватает слов, чтобы найти его.
scala> Seq[Any]( 3, 3.4 )
res0: Seq[Any] = List(3, 3.4)
scala> res0( 1 ).getClass
res1: Class[_] = class java.lang.Double
scala> Seq( 3, 3.4 )
res2: Seq[Double] = List(3.0, 3.4)
scala> res2( 1 ).getClass
res3: Class[Double] = double
Почему Скала обрабатывает мой Double
ввод как java.lang.Double
в пределах Seq[Any]
но держит это как scala.Double
при работе с Seq[AnyRef]
? Есть ли способ предотвратить такое поведение и вместо этого всегда использовать типы Scala?
2 ответа
В Scala Double
соответствует Java double
но может получить автоматическую коробку и распакованы при необходимости, и это становится java.lang.Double
когда он будет автоматически упакован. На практике для коллекций требуется автобокс примитивных переменных.
Типы коллекций, которые вы объявляете, выводятся на основании назначенного им значения, если тип не объявлен явно. Разница между двумя декларациями в вопросе заключается в том, что для Seq(value1,value2,...)
вывод типа пытается найти "лучший" тип, придумывает Seq[Double]
а потом интересует value1
, value2
и так далее на основе этого типа (Scala Double
). Если вы объявите тип явно как Seq[Any]
, вывод типа не выполняется (так как вы сами дали тип), и поэтому значения value1
, value2
и т. д. не "вынуждены" интерпретироваться как имеющие фиксированный тип.
поскольку Seq
является коллекцией, примитивы не допускаются и должны быть автоматически упакованы, поэтому Java double
не может вписаться в то время как java.lang.Double
Можно. Логика, которая пытается скрыть бокс и распаковку для Seq[Double]
и прозрачно меняет примитив, и объект не входит в игру. На самом деле, в Seq[Any]
каждый элемент может быть другого типа, что означает, что такой бокс и распаковка не могут работать в общем случае (в вашем примере, res0(0).getClass
является Integer
в отличие от res2(0).getClass
который является двойным).
Таким образом, по сути, если вы не объявляете тип явно, вывод типа включается и сначала пытается найти общий тип для всех элементов коллекции, а затем преобразует все элементы в этот тип, в то время как параметр типа коллекции указан явно, ничего подобного не происходит, и все типы значений интерпретируются как "необработанные".
То, что происходит, это бокс. Потому что первый Seq[Any]
Любые примитивы в нем будут возвращаться в коробочном виде. Во втором случае, потому что тип Seq[Double]
, доступ к участникам будет автоматически распакован (но все равно будет сохранен в Seq
).
Попытка получить класс времени выполнения для примитивов неизбежно вызовет всевозможные проблемы. Попробуйте не нужно использовать getClass
,