Как создать гетерогенный массив в Scala?
В javascript мы можем сделать:
["a string", 10, {x : 1}, function() {}].push("another value");
Что такое эквивалент Scala?
Ответы
Ответ 1
Массивы в Scala очень однородны. Это связано с тем, что Scala является статически типизированным языком. Если вам действительно нужны псевдогетерогенные функции, вам нужно использовать неизменяемую структуру данных, которая ковариационно параметризована (наиболее непреложные структуры данных). List
- это канонический пример, но Vector
также является опцией. Затем вы можете сделать что-то вроде этого:
Vector("a string", 10, Map("x" -> 1), ()=>()) + "another value"
Результат будет иметь тип Vector[Any]
. Не очень полезно с точки зрения статического ввода текста, но все будет там, как и было обещано.
Кстати, "литеральный синтаксис" для массивов в Scala выглядит следующим образом:
Array(1, 2, 3, 4) // => Array[Int] containing [1, 2, 3, 4]
См. также: Дополнительная информация о постоянных векторах
Ответ 2
Scala выберет наиболее специфичный тип элемента Array, который может содержать все значения, в этом случае ему нужен наиболее общий тип Any
, который является супертипом любого другого типа:
Array("a string", 10, new { val x = 1 }, () => ()) :+ "another value"
Результирующий массив будет иметь тип Array[Any]
.
Ответ 3
Scala может вскоре получить возможность "гетерогенного" списка:
HList в Scala
Ответ 4
Лично я бы, вероятно, использовал кортежи, поскольку herom упоминает в комментарии.
scala> ("a string", 10, (1), () => {})
res1: (java.lang.String, Int, Int, () => Unit) = (a string,10,1,<function0>)
Но вы не можете легко добавлять такие структуры.
HList, упомянутый ePharaoh, "сделан для этого", но я, вероятно, остался бы в стороне от него сам. Это тяжелое программирование по типу и, следовательно, может нести с собой удивительные нагрузки (т.е. Создавать множество классов при компиляции). Просто будь осторожен. HList из вышеперечисленного (требуется библиотека MetaScala) (не доказано, поскольку я не использую MetaScala):
scala> "a string" :: 10 :: (1) :: () => {} :: HNil
Вы можете добавить и т.д. (ну, по крайней мере, добавить) к такому списку, и он будет знать типы. Prepending создает новый тип, который имеет старый тип как хвост.
Тогда один подход еще не упоминался. Классы (особенно классы классов) очень легкие на Scala, и вы можете сделать их как однострочные:
scala> case class MyThing( str: String, int: Int, x: Int, f: () => Unit )
defined class MyThing
scala> MyThing( "a string", 10, 1, ()=>{} )
res2: MyThing = MyThing(a string,10,1,<function0>)
Конечно, это тоже не будет обрабатывать.