Подтвердить что ты не робот

Почему нет неизменяемых массивов в стандартной библиотеке scala?

Scala имеет всевозможные виды неизменяемых последовательностей, таких как List, Vector и т.д. Я был удивлен тем, что не нашел реализации неизменяемой индексированной последовательности, поддерживаемой простым массивом (вектор кажется слишком сложным для моих нужд).

  • Есть ли причина для этого? Я не мог найти хорошее объяснение в списке рассылки.

  • Есть ли у вас рекомендация по неизменяемой индексированной последовательности, которая близка к тем же характеристикам, что и массив? Я рассматриваю scalaz ImmutableArray, но у него есть некоторые проблемы с scala стволом, например.

Спасибо

4b9b3361

Ответ 1

Вы можете преобразовать массив в последовательность.

val s: Seq[Int] = Array(1,2,3,4)

Массив будет неявно преобразован в WrappedArray. И поскольку тип Seq, операции обновления больше не будут доступны.

Ответ 2

Итак, сначала сделайте различие между интерфейсом и классом. Интерфейс представляет собой API-интерфейс, а класс - это реализация такого API.

Интерфейсы в Scala имеют одно и то же имя и разные пакеты, чтобы отличить их от неизменяемости: Seq, immutable.Seq, mutable.Seq.

С другой стороны, классы, как правило, не имеют имени. A List является неизменной последовательностью, а a ListBuffer является изменяемой последовательностью. Существуют исключения, например HashSet, но это просто совпадение в отношении реализации.

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

Интерфейс, реализованный с помощью WrappedArray, является IndexedSeq, который существует как изменяемые, так и неизменные.

immutable.IndexedSeq имеет несколько реализующих классов, включая WrappedString. Однако общий класс реализации, использующий его, - это Vector. Этот класс занимает ту же позицию, что класс Array будет занимать переменную сторону.

Теперь нет больше сложностей в использовании Vector, чем при использовании Array, поэтому я не знаю, почему вы называете это сложным.

Возможно, вы думаете, что он слишком много внутренне, и в этом случае вы ошибаетесь. Все хорошо разработанные неизменяемые классы persistent, потому что использование неизменяемой коллекции означает создание новых копий, поэтому их нужно оптимизировать для этого, что и делает Vector.

Ответ 3

В основном потому, что в Scala нет никаких массивов. То, что вы видите, - это массивы java, укутанные несколькими методами, которые помогают им вписаться в API коллекции.

Все остальное не будет массивом, с его уникальным свойством не страдания стирания стилей или сломанной дисперсией. Это будет просто другой тип с индексами и значениями. Scala имеет это, он называется IndexedSeq, и если вам нужно передать его как массив некоторым сторонним API, вы можете просто использовать .toArray

Ответ 4

В Scala 2.13 добавлено ArraySeq, которое является неизменной последовательностью, поддерживаемой массивом.

Ответ 5

Точка класса scala Array должна обеспечить механизм доступа к возможностям массивов Java (но без решения > , позволяющего массивам быть ковариантными в своей системе типов). Массивы Java изменяемы, поэтому также находятся в стандартной библиотеке scala.

Предположим, что в библиотеке был еще один класс immutable.Array, но компилятор также должен был использовать массив Java в качестве базовой структуры (для эффективности/скорости). После этого компиляция и запуск следующего кода:

val i = immutable.Array("Hello")
i.asInstanceOf[Array[String]](0) = "Goodbye"
println( i(0) ) //I thought i was immutable :-(

То есть, массив действительно изменился бы.

Ответ 6

Проблема с массивами заключается в том, что они имеют фиксированный размер. Нет операции для добавления элемента в массив или удаления его из него.

Вы можете сохранить массив, который, по вашему мнению, будет достаточно длинным, как хранилище резервных копий, "растрачивает" память, которую вы не используете, отслеживать последний использованный индекс и копировать в более крупный массив, если вам нужно дополнительное пространство. Очевидно, что это копирование O(N).

Изменение одного элемента также O(N), поскольку вам нужно будет скопировать весь массив. Структурное разделение отсутствует, что является основой функциональных структур данных.

Вы также можете выделить дополнительный массив для "переполненных" элементов и как-то отслеживать свои массивы. В этот момент вы на своем пути изобретаете Vector.

Короче говоря, из-за их непригодности для структурного обмена неизменные фасады для массивов имеют ужасные рабочие характеристики во время выполнения для большинства обычных операций, таких как добавление элемента, удаление элемента и изменение элемента.

Это только оставляет прецедент фиксированного размера носителя данных с фиксированным размером, и этот случай использования относительно редок. В большинстве случаев лучше использовать List, Stream или Vector