it-swarm.com.ru

Как мне создать гетерогенный массив в Scala?

В javascript мы можем сделать:

["a string", 10, {x : 1}, function() {}].Push("another value");

Что эквивалентно Scala?

28
Leo

Массивы в 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]

См. Также : Подробнее о постоянных векторах

40
Daniel Spiewak

Scala выберет наиболее конкретный тип элемента Array, который может содержать все значения, в этом случае ему нужен самый общий тип Any, который является супертипом любого другого типа:

Array("a string", 10, new { val x = 1 }, () => ()) :+ "another value"

Полученный массив будет иметь тип Array[Any].

18
soc

Scala может вскоре получить возможность создания "разнородного" списка: HList in Scala

4
ePharaoh

Лично я, вероятно, использовал бы кортежи, как упоминает 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>)

Конечно, это не справится и с добавлением.

2
akauppi