Ответ 1
Предисловие
Там есть коллекция коллекций 2.8 от Мартина Одерски, которая, вероятно, должна быть вашей первой ссылкой. Он также дополнен архитектурными примечаниями , что будет представлять особый интерес для тех, кто хочет создавать собственные коллекции.
Остальная часть этого ответа была написана до того, как существовала такая вещь (на самом деле, до того, как сама версия 2.8.0 была выпущена).
Вы можете найти статью об этом как Scala SID # 3. Другие статьи в этой области также должны быть интересны людям, заинтересованным в различиях между Scala 2.7 и 2.8.
Я цитирую из статьи выборочно и дополняю мои мысли. Также есть некоторые изображения, созданные Matthias на decodified.com, а исходные файлы SVG можно найти здесь.
Сами классы/черты коллекции
На самом деле существует три иерархии черт для коллекций: одна для изменяемых коллекций, одна для неизменяемых коллекций и та, которая не делает никаких предположений о коллекциях.
Также существует различие между параллельными, последовательными и, возможно, параллельными коллекциями, которые были введены с помощью Scala 2.9. Я расскажу о них в следующем разделе. Иерархия, описанная в этом разделе, относится исключительно к непараллельным коллекциям.
На следующем рисунке показана нестандартная иерархия, введенная с помощью Scala 2.8:
Все отображаемые элементы являются чертами. В двух других иерархиях также есть классы, непосредственно наследующие черты, а также классы, которые можно рассматривать как принадлежащие к этой иерархии через неявное преобразование в классы-оболочки. Легенда для этих графиков может быть найдена после них.
График для неизменяемой иерархии:
График для изменяемой иерархии:
Условные обозначения:
Здесь приведено сокращенное ASCII изображение иерархии коллекции для тех, кто не видит изображения.
Traversable
|
|
Iterable
|
+------------------+--------------------+
Map Set Seq
| | |
| +----+----+ +-----+------+
Sorted Map SortedSet BitSet Buffer Vector LinearSeq
Параллельные коллекции
Когда Scala 2.9 вводили параллельные коллекции, одна из целей дизайна заключалась в том, чтобы сделать их использование максимально бесшовным. Проще говоря, можно заменить непараллельную (последовательную) коллекцию параллельной и мгновенно воспользоваться преимуществами.
Однако, поскольку все коллекции до этого были серийными, многие алгоритмы с их использованием предполагались и зависели от того, что они были серийными. Параллельные коллекции, полученные для методов с такими предположениями, потерпят неудачу. По этой причине вся иерархия, описанная в предыдущем разделе, требует последовательной обработки.
Для поддержки параллельных коллекций были созданы две новые иерархии.
Иерархия параллельных коллекций имеет одинаковые имена для признаков, но ей предшествуют Par
: ParIterable
, ParSeq
, ParMap
и ParSet
. Обратите внимание, что нет ParTraversable
, поскольку любая коллекция, поддерживающая параллельный доступ, способна поддерживать более сильную черту ParIterable
. Он не имеет некоторых более специализированных признаков, присутствующих в последовательной иерархии. Вся эта иерархия находится в каталоге scala.collection.parallel
.
Классы, реализующие параллельные коллекции, также различаются: ParHashMap
и ParHashSet
для изменяемых и неизменяемых параллельных коллекций плюс ParRange
и ParVector
реализация immutable.ParSeq
и ParArray
реализации mutable.ParSeq
.
Также существует другая иерархия, которая отражает черты последовательных и параллельных коллекций, но с префиксом Gen
: GenTraversable
, GenIterable
, GenSeq
, GenMap
и GenSet
. Эти черты являются родителями как для параллельных, так и для последовательных коллекций. Это означает, что метод, принимающий Seq
, не может получать параллельный набор, но ожидается, что метод, принимающий GenSeq
, будет работать как с последовательными, так и с параллельными коллекциями.
Учитывая способ структурирования этих иерархий, код, написанный для Scala 2.8, полностью совместим с Scala 2.9 и требует последовательного поведения. Не переписываясь, он не может использовать параллельные коллекции, но требуемые изменения очень малы.
Использование параллельных коллекций
Любая коллекция может быть преобразована в параллельную, вызвав на ней метод Par
. Аналогично, любая коллекция может быть преобразована в последовательную, вызвав на ней метод Seq
.
Если коллекция уже была запрошенной (параллельной или последовательной), конверсия не будет выполнена. Если вы вызываете Seq
в параллельной коллекции или Par
в последовательном наборе, то создается новая коллекция с запрошенным признаком.
Не путайте Seq
, который превращает коллекцию в непараллельный коллектив с toSeq
, который возвращает Seq
, созданный из элементов коллекции. Вызов toSeq
в параллельном наборе возвращает ParSeq
, а не последовательную коллекцию.
Основные черты
Несмотря на то, что существует множество классов реализации и подделок, в иерархии есть некоторые основные черты, каждая из которых предоставляет больше методов или более конкретные гарантии, но уменьшает количество классов, которые могут их реализовать.
В следующих подразделах я дам краткое описание основных черт и идей, стоящих за ними.
Trait TraversableOnce
Эта черта в значительной степени похожа на признак Traversable
, описанный ниже, но с ограничением, которое вы можете использовать только один раз. То есть любые методы, вызываемые в TraversableOnce
, могут сделать его непригодным.
Это ограничение позволяет использовать одни и те же методы между коллекциями и Iterator
. Это позволяет использовать метод Iterator
, но не используя Iterator
-специфические методы, чтобы фактически иметь возможность работать с любой коллекцией вообще, плюс итераторы, если они были перезаписаны для принятия TraversableOnce
.
Поскольку TraversableOnce
объединяет коллекции и итераторы, он не отображается на предыдущих графиках, которые относятся только к коллекциям.
Trait Traversable
В верхней части иерархии коллекции есть символ Traversable
. Его единственная абстрактная операция
def foreach[U](f: Elem => U)
Операция предназначена для перемещения всех элементов коллекции и применения данной операции f к каждому элемент. Приложение выполняется только для его побочного эффекта; на самом деле любой результат функции f отбрасывается Еогеасп.
Трассируемые объекты могут быть конечными или бесконечными. Примером бесконечного проходящего объекта является поток
натуральных чисел Stream.from(0)
. Метод hasDefiniteSize
указывает, возможно ли сбор
бесконечна. Если hasDefiniteSize
возвращает true, коллекция конечно конечно. Если он возвращает false,
коллекция еще не была до конца разработана, поэтому она может быть бесконечной или конечной.
Этот класс определяет методы, которые могут быть эффективно реализованы в терминах foreach
(более 40 из них).
Итерируемый результат
Эта черта объявляет абстрактный метод Iterator
, который возвращает итератор, который дает все элементы коллекций по одному. Метод foreach
в Iterable
реализован в терминах Iterator
. Подклассы Iterable
часто переопределяют foreach с прямой реализацией для эффективности.
Класс Iterable
также добавляет некоторые менее часто используемые методы к Traversable
, которые могут быть эффективно реализованы только в том случае, если доступен Iterator
. Они приведены ниже.
xs.iterator An iterator that yields every element in xs, in the same order as foreach traverses elements.
xs takeRight n A collection consisting of the last n elements of xs (or, some arbitrary n elements, if no order is defined).
xs dropRight n The rest of the collection except xs takeRight n.
xs sameElements ys A test whether xs and ys contain the same elements in the same order
Другие черты
После Iterable
появляются три базовые черты, которые наследуют от него: Seq
, Set
и Map
. Все три имеют метод apply
, и все три реализуют черту PartialFunction
, но значение apply
отличается в каждом случае.
Я верю, что значение Seq
, Set
и Map
является интуитивным. После них классы разбиваются на конкретные реализации, которые предоставляют определенные гарантии в отношении производительности и методы, которые она предоставляет в результате. Также доступны некоторые черты с дополнительными уточнениями, такими как LinearSeq
, IndexedSeq
и SortedSet
.
Нижеприведенный список может быть улучшен. Оставьте комментарий с предложениями, и я исправлю его.
Базовые классы и черты
-
Traversable
- Основной класс коллекции. Может быть реализовано с помощьюforeach
.-
TraversableProxy
- Прокси дляTraversable
. Просто укажитеself
на реальную коллекцию. -
TraversableView
- A Traversable с некоторыми нестрогими методами. -
TraversableForwarder
- перенаправляет большинство методов наunderlying
, кромеtoString
,hashCode
,equals
,stringPrefix
,newBuilder
,view
и всех вызовов, создающих новый итерируемый объект такой же вид. -
mutable.Traversable
иimmutable.Traversable
- то же самое, что иTraversable
, но ограничение типа коллекции. - Существуют другие специальные случаи
Iterable
, такие какMetaData
. -
Iterable
- Коллекция, для которой можно создатьIterator
(черезIterator
).-
IterableProxy
,IterableView
,mutable
иimmutable.Iterable
.
-
-
-
Iterator
- черта, которая не является потомкомTraversable
. Определитеnext
иhasNext
.-
CountedIterator
-Iterator
, определяющийcount
, который возвращает элементы, видимые до сих пор. -
BufferedIterator
- Определяетhead
, который возвращает следующий элемент, не потребляя его. - Существуют другие специальные случаи
Iterator
, такие какSource
.
-
Карты
-
Map
-Iterable
Tuple2
, который также предоставляет методы для получения значения (второго элемента кортежа) с заданной клавишей (первый элемент кортежа). РасширяетPartialFunction
.-
MapProxy
- AProxy
для aMap
. -
DefaultMap
- черта, реализующая некоторые абстрактные методыMap
. -
SortedMap
- AMap
, ключи которого отсортированы.-
immutable.SortMap
-
immutable.TreeMap
- класс, реализующийimmutable.SortedMap
.
-
-
-
immutable.Map
-
immutable.MapProxy
-
immutable.HashMap
- класс, реализующийimmutable.Map
посредством хэширования ключей. -
immutable.IntMap
- класс, реализующийimmutable.Map
, специализированный для ключейInt
. Использует дерево на основе двоичных цифр ключей. -
immutable.ListMap
- класс, реализующийimmutable.Map
через списки. -
immutable.LongMap
- класс, реализующийimmutable.Map
специализированный для ключейLong
. См.IntMap
. - Существуют дополнительные классы, оптимизированные для определенного количества элементов.
-
-
mutable.Map
-
mutable.HashMap
- класс, реализующийmutable.Map
через хэширование ключей. -
mutable.ImmutableMapAdaptor
- класс, реализующийmutable.Map
из существующегоimmutable.Map
. -
mutable.LinkedHashMap
-? -
mutable.ListMap
- класс, реализующийmutable.Map
через списки. -
mutable.MultiMap
- класс, принимающий более одного отдельного значения для каждого ключа. -
mutable.ObservableMap
- Mixin, который при смешивании сMap
публикует события для наблюдателей через интерфейсPublisher
. -
mutable.OpenHashMap
- класс, основанный на алгоритме открытого хэширования. -
mutable.SynchronizedMap
- Mixin, который должен быть смешан сMap
, чтобы предоставить его версию с синхронизированными методами. -
mutable.MapProxy
.
-
-
Последовательности
-
Seq
- последовательность элементов. Предполагается четко определенный размер и повторение элементов. РасширяетPartialFunction
.-
IndexedSeq
- Последовательности, поддерживающие доступ к элементу O (1) и вычисление длины O (1).-
IndexedSeqView
-
immutable.PagedSeq
- реализацияIndexedSeq
, где элементы создаются по запросу функцией, переданной через конструктор. -
immutable.IndexedSeq
-
immutable.Range
- Разделенная последовательность целых чисел, закрытая на нижнем конце, открыта на верхнем конце и с шагом.-
immutable.Range.Inclusive
- ARange
также закрыт на верхнем конце. -
immutable.Range.ByOne
- ARange
, чей шаг равен 1.
-
-
immutable.NumericRange
- более общая версияRange
, которая работает с любымIntegral
.-
immutable.NumericRange.Inclusive
,immutable.NumericRange.Exclusive
. -
immutable.WrappedString
,immutable.RichString
- Wrappers, который позволяет видетьString
какSeq[Char]
, сохраняя при этом методыString
. Я не уверен, какая разница между ними.
-
-
-
mutable.IndexedSeq
-
mutable.GenericArray
- структура, подобная массивуSeq
. Обратите внимание, что "класс"Array
- это JavaArray
, который больше относится к способу хранения данных, чем к классу. -
mutable.ResizableArray
- Внутренний класс, используемый классами на основе изменяемых размеров массивов. -
mutable.PriorityQueue
,mutable.SynchronizedPriorityQueue
- классы, реализующие приоритетные очереди - очереди, в которых элементы сначала выгружаются в соответствии сOrdering
, и порядок очередей. -
mutable.PriorityQueueProxy
- абстрактныйProxy
дляPriorityQueue
.
-
-
-
LinearSeq
- признак линейных последовательностей с эффективным временем дляisEmpty
,head
иtail
.-
immutable.LinearSeq
-
immutable.List
- Неизменяемая, односвязная реализация списка. -
immutable.Stream
- ленивый список. Его элементы вычисляются только по требованию, но затем запоминаются (хранятся в памяти). Это может быть теоретически бесконечно.
-
-
mutable.LinearSeq
-
mutable.DoublyLinkedList
- Список с изменяемымиprev
,head
(elem
) иtail
(next
). -
mutable.LinkedList
- Список с изменяемымhead
(elem
) иtail
(next
). -
mutable.MutableList
- класс, используемый внутри для реализации классов на основе измененных списков.-
mutable.Queue
,mutable.QueueProxy
- структура данных, оптимизированная для операций FIFO (First-In, First-Out). -
mutable.QueueProxy
- AProxy
для amutable.Queue
.
-
-
-
-
SeqProxy
,SeqView
,SeqForwarder
-
immutable.Seq
-
immutable.Queue
- класс, реализующий структуру данных с оптимизацией FIFO (First-In, First-Out). Не существует общего суперкласса для очередейmutable
иimmutable
. -
immutable.Stack
- класс, реализующий LIFO-оптимизированную структуру данных (Last-In, First-Out). Нет общего суперкласса как стековmutable
immutable
. -
immutable.Vector
-? -
scala.xml.NodeSeq
- специализированный XML-класс, который расширяетimmutable.Seq
. -
immutable.IndexedSeq
- Как видно выше. -
immutable.LinearSeq
- Как видно выше.
-
-
mutable.ArrayStack
- класс, реализующий LIFO-оптимизированную структуру данных с использованием массивов. Предположительно значительно быстрее обычного стека. -
mutable.Stack
,mutable.SynchronizedStack
- Классы, реализующие структуру данных с оптимизацией LIFO. -
mutable.StackProxy
- AProxy
для amutable.Stack
.. -
mutable.Seq
-
mutable.Buffer
- Последовательность элементов, которые могут быть изменены добавлением, добавлением или вставкой новых членов.-
mutable.ArrayBuffer
- реализация классаmutable.Buffer
с постоянным временем амортизации для операций добавления, обновления и произвольного доступа. Он имеет некоторые специализированные подклассы, такие какNodeBuffer
. -
mutable.BufferProxy
,mutable.SynchronizedBuffer
. -
mutable.ListBuffer
- буфер, поддерживаемый списком. Он обеспечивает постоянное добавление времени и добавление, при этом большинство других операций являются линейными. -
mutable.ObservableBuffer
- признак mixin, который при смешивании сBuffer
предоставляет события уведомлений через интерфейсыPublisher
. -
mutable.IndexedSeq
- Как видно выше. -
mutable.LinearSeq
- Как видно выше.
-
-
-
Наборы
-
Set
- Набор представляет собой набор, включающий не более одного из любого объекта.-
BitSet
- набор целых чисел, хранящихся в битах.-
immutable.BitSet
-
mutable.BitSet
-
-
SortedSet
- набор, элементы которого упорядочены.-
immutable.SortedSet
-
immutable.TreeSet
- реализацияSortedSet
на основе дерева.
-
-
-
SetProxy
- AProxy
для aSet
. -
immutable.Set
-
immutable.HashSet
- реализацияSet
на основе хеширования элементов. -
immutable.ListSet
- реализацияSet
на основе списков. - Дополнительные классы классов существуют для обеспечения оптимизированных реализаций для наборов от 0 до 4 элементов.
-
immutable.SetProxy
- AProxy
для неизменяемогоSet
.
-
-
mutable.Set
-
mutable.HashSet
- реализацияSet
на основе хеширования элементов. -
mutable.ImmutableSetAdaptor
- класс, реализующий изменяемыйSet
из неизменяемогоSet
. -
LinkedHashSet
- реализацияSet
на основе списков. -
ObservableSet
- признак mixin, который при смешивании сSet
предоставляет события уведомлений через интерфейсPublisher
. -
SetProxy
- AProxy
для aSet
. -
SynchronizedSet
- признак mixin, который при смешивании сSet
предоставляет события уведомлений через интерфейсPublisher
.
-
-
- Почему существуют классы Like (например, TraversableLike)
Это было сделано для достижения максимального повторного использования кода. Конкретная общая реализация для классов с определенной структурой (обходная, карта и т.д.) Выполняется в классах Like. Затем классы, предназначенные для общего потребления, переопределяют выбранные методы, которые могут быть optmized.
- Что представляют собой методы компаньона (например, List.companion)
Создатель для классов, т.е. объект, который знает, как создавать экземпляры этого класса таким образом, который может использоваться такими методами, как Map
, создается методом в объекте-компаньоне. Итак, чтобы построить объект типа X, мне нужно получить этот строитель из сопутствующего объекта X. К сожалению, нет способа в Scala перейти от класса X к объекту X. Из-за этого, существует метод, определенный в каждом экземпляре X, companion
, который возвращает объект-компаньон класса X.
Хотя в обычных программах может быть какое-то использование для такого метода, его целью является повторное использование кода в библиотеке коллекции.
- Как я знаю, какие неявные объекты находятся в области видимости в данной точке
Вы не должны заботиться об этом. Они неявны именно так, что вам не нужно выяснять, как заставить его работать.
Эти импликации существуют, чтобы позволить методам в коллекциях быть определенными в родительских классах, но все равно возвращать коллекцию того же типа. Например, метод Map
определен в TraversableLike
, но если вы использовали на List
, вы получите List
назад.