Первый список имеет тип List[Double]
из-за расширения литерального типа. Скала видит литералы и отмечает, что, хотя они бывают разных типов, их можно объединить, расширив некоторые из них. Если бы не было расширения типа, то был бы принят самый распространенный суперкласс, AnyVal
.
List(1.1 /* Double literal */), 3 /* Int literal */)
Второй список явно List[Int]
, хотя явный вызов Double
приведет к расширению типа для литералов.
List(5 /* Int literal */, 7 /* Int literal */)
Теперь важно отметить, что расширение типов - это то, что происходит во время compile . Скомпилированный код не будет содержать Int
3, только Double
3.0. Однако после создания списка расширение типов становится невозможным, поскольку хранимые объекты на самом деле разные.
Итак, после того, как вы объедините два списка, результирующий тип будет суперклассом Double
и Int
. А именно, AnyVal
. Однако в результате взаимодействия Java AnyVal
не может содержать никаких полезных методов (таких как числовые операторы).
Мне интересно, что делает Clojure внутри. Преобразует ли это целые числа в двойники при конкатенации? Или он хранит все как Object
(как это делает Scala), но имеет более умные математические операторы?