my breathless confusion に続いて、新しい Scala2.8コレクションライブラリが構造化されました。以下がどのように組み合わされるかについていくつかの情報を見つけたいです。
List
、Iterable
)TraversableLike
)List.companion
)implicit
オブジェクトを知る方法Martin Oderskyによる 2.8コレクションのウォークスルー があり、これがおそらく最初の参照になるはずです。 architectural notes も追加されています。これは、独自のコレクションをデザインしたい人にとって特に興味深いものです。
この回答の残りの部分は、そのようなものが存在する前(実際には2.8.0自体がリリースされる前)に書かれました。
それについての論文は Scala SID# として見つけることができます。その分野の他の論文は、Scala 2.7と2.8の違いに興味がある人々にとっても興味深いでしょう。
論文から引用し、選択的に、そして私の考えを補足する。 decodified.comのMatthiasによって生成されたいくつかの画像もあり、元のSVGファイルは here で見つけることができます。
コレクションには、実際には3つの特性階層があります。1つは変更可能なコレクション、1つは不変のコレクション、もう1つはコレクションについて何も想定していません。
Scala 2.9で導入された、並列、シリアル、多分並列のコレクションの違いもあります。これらについては、次のセクションで説明します。このセクションで説明する階層は、 非並列コレクション専用。
次の画像は、Scala 2.8で導入された非特定の階層を示しています。
示されているすべての要素は特性です。他の2つの階層には、特性を直接継承するクラスと、ラッパークラスへの暗黙的な変換によってその階層に属するviewed asが可能なクラスもあります。これらのグラフの凡例は、それらの後にあります。
不変階層のグラフ:
可変階層のグラフ:
伝説:
画像を見ることができない人のために、ここにASCIIコレクション階層の図を示します。
_ Traversable
|
|
Iterable
|
+------------------+--------------------+
Map Set Seq
| | |
| +----+----+ +-----+------+
Sorted Map SortedSet BitSet Buffer Vector LinearSeq
_
Scala 2.9が並列コレクションを導入した場合、設計目標の1つは、それらの使用を可能な限りシームレスにすることでした。最も簡単に言えば、非並列(シリアル)コレクションを並列コレクションに置き換えることができます。 1つで、すぐにメリットを享受できます。
ただし、それまでのすべてのコレクションはシリアルだったため、それらを使用する多くのアルゴリズムは、それらがあったシリアルであると想定し、それに依存していました。このような前提でメソッドに供給された並列コレクションは失敗します。このため、前のセクションで説明したすべての階層シリアル処理が必須です。
並列コレクションをサポートするために、2つの新しい階層が作成されました。
並列コレクション階層は、特性の名前は同じですが、前にPar
が付いています:ParIterable
、ParSeq
、ParMap
、ParSet
。並列アクセスをサポートするコレクションは、より強力なParTraversable
特性をサポートできるため、ParIterable
がないことに注意してください。また、シリアル階層に存在する、より特化した特性もいくつかありません。この階層全体は、ディレクトリ_scala.collection.parallel
_の下にあります。
並列コレクションを実装するクラスも異なります。可変および不変の両方の並列コレクションのParHashMap
およびParHashSet
に加えて、_immutable.ParSeq
_を実装するParRange
およびParVector
および_mutable.ParSeq
_を実装するParArray
です。
シリアルおよびパラレルコレクションの特性を反映する別の階層も存在しますが、プレフィックスGen
:GenTraversable
、GenIterable
、GenSeq
、GenMap
およびGenSet
が付いています。これらの特性はparentsであり、パラレルコレクションとシリアルコレクションの両方に対応します。つまり、Seq
を取得するメソッドは並列コレクションを受け取ることができませんが、GenSeq
を取得するメソッドは、シリアルコレクションと並列コレクションの両方で機能することが期待されます。
これらの階層の構造を考えると、Scala 2.8向けに記述されたコードはScala 2.9と完全に互換性があり、シリアル動作を要求しました。書き直さない限り、並列コレクションの利点ですが、必要な変更はごくわずかです。
コレクションでpar
メソッドを呼び出すことにより、コレクションをパラレルコレクションに変換できます。同様に、コレクションでseq
メソッドを呼び出すことにより、コレクションをシリアルコレクションに変換できます。
コレクションがすでに要求されたタイプ(パラレルまたはシリアル)であった場合、変換は行われません。ただし、パラレルコレクションでseq
を呼び出すか、シリアルコレクションでpar
を呼び出すと、要求された特性を持つ新しいコレクションが生成されます。
コレクションを非並列コレクションに変換するseq
と、コレクションの要素から作成されたtoSeq
を返すSeq
を混同しないでください。並列コレクションでtoSeq
を呼び出すと、シリアルコレクションではなくParSeq
が返されます。
多くの実装クラスとサブトレイトがありますが、階層にはいくつかの基本的なトレイトがあり、それぞれがより多くのメソッドまたはより具体的な保証を提供しますが、それらを実装できるクラスの数は減少します。
次のサブセクションでは、主な特性とその背後にある考え方について簡単に説明します。
このトレイトは、以下に説明するトレイトTraversable
によく似ていますが、使用できるという制限がありますonce。つまり、TraversableOnce
mayで呼び出されたメソッドは、使用できなくなります。
この制限により、同じメソッドをコレクションとIterator
間で共有できるようになります。これにより、Iterator
に対応しているがIterator
固有のメソッドを使用していないメソッドが実際にすべてのコレクションを処理できるようになり、TraversableOnce
を受け入れるように書き換えるとイテレータを使用できます。
TraversableOnce
はコレクションとイテレータを統合するため、コレクションのみに関係する前のグラフには表示されません。
コレクション階層の最上位は、特性Traversable
です。その唯一の抽象的な操作は
_def foreach[U](f: Elem => U)
_
この操作は、コレクションのすべての要素をトラバースし、指定された操作fを各要素に適用することを目的としています。アプリケーションは、その副作用のためにのみ行われます。実際、fの関数結果はforeachによって破棄されます。
トラバース可能なオブジェクトには、有限のものと無限のものがあります。無限のトラバース可能なオブジェクトの例は、自然数のストリームStream.from(0)
です。メソッドhasDefiniteSize
は、コレクションが無限であるかどうかを示します。 hasDefiniteSize
がtrueを返す場合、コレクションは確かに有限です。 falseが返される場合、コレクションはまだ完全に作成されていないため、無限または有限である可能性があります。
このクラスは、foreach
(40以上)の観点から効率的に実装できるメソッドを定義します。
このトレイトは、すべてのコレクションの要素を1つずつ生成するイテレータを返す抽象メソッド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
の3つの基本特性が継承されます。 3つすべてにapply
メソッドがあり、3つすべてがPartialFunction
特性を実装していますが、apply
の意味はそれぞれの場合で異なります。
Seq
、Set
、Map
の意味は直感的です。その後、クラスは、パフォーマンス、およびその結果として利用可能になるメソッドに関して特定の保証を提供する特定の実装に分割されます。 LinearSeq
、IndexedSeq
、SortedSet
など、さらに改良された特性もあります。
以下のリストは改善される可能性があります。提案とともにコメントを残してください。修正します。
Traversable
-基本的なコレクションクラス。 foreach
。だけで実装できますTraversableProxy
-Traversable
のプロキシ。 self
に実際のコレクションを指定するだけです。TraversableView
-いくつかの非厳密なメソッドを持つ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
-_Tuple2
_のIterable
。これは、キー(タプルの最初の要素)を指定して値(タプルの2番目の要素)を取得するためのメソッドも提供します。 PartialFunction
も拡張します。MapProxy
-Proxy
のMap
。DefaultMap
-Map
の抽象メソッドの一部を実装する特性。SortedMap
-キーがソートされるMap
。immutable.SortMap
_ immutable.TreeMap
_-_immutable.SortedMap
_を実装するクラス。immutable.Map
_ immutable.MapProxy
_immutable.HashMap
_-キーハッシュを介して_immutable.Map
_を実装するクラス。immutable.IntMap
_-Int
キーに特化した_immutable.Map
_を実装するクラス。キーの2進数に基づくツリーを使用します。immutable.ListMap
_-リストを通じて_immutable.Map
_を実装するクラス。immutable.LongMap
_-Long
キーに特化した_immutable.Map
_を実装するクラス。 IntMap
を参照してください。mutable.Map
_ mutable.HashMap
_-キーハッシュを介して_mutable.Map
_を実装するクラス。mutable.ImmutableMapAdaptor
_-既存の_mutable.Map
_から_immutable.Map
_を実装するクラス。mutable.LinkedHashMap
_-?mutable.ListMap
_-リストを通じて_mutable.Map
_を実装するクラス。mutable.MultiMap
_-各キーに対して複数の異なる値を受け入れるクラス。mutable.ObservableMap
_-A mixinは、Map
と混合すると、Publisher
インターフェースを介してオブザーバーにイベントを発行します。mutable.OpenHashMap
_-オープンハッシュアルゴリズムに基づくクラス。mutable.SynchronizedMap
_-A mixinMap
と混合して、同期されたメソッドを備えたバージョンを提供する必要があります。mutable.MapProxy
_。Seq
-要素のシーケンス。明確に定義されたサイズと要素の繰り返しを想定しています。 PartialFunction
も拡張します。IndexedSeq
-O(1)要素へのアクセスとO(1)長さの計算。をサポートするシーケンスIndexedSeqView
immutable.PagedSeq
_-IndexedSeq
の実装。要素は、コンストラクタを介して渡される関数によってオンデマンドで生成されます。immutable.IndexedSeq
_ immutable.Range
_-区切られた整数のシーケンス。下端で閉じ、上端で開き、ステップ付き。immutable.Range.Inclusive
_-Range
もハイエンドでクローズされました。immutable.Range.ByOne
_-ステップが1のRange
.immutable.NumericRange
_-Range
で機能するIntegral
のより一般的なバージョン。immutable.NumericRange.Inclusive
_、_immutable.NumericRange.Exclusive
_。immutable.WrappedString
_、_immutable.RichString
_-String
メソッドを保持しながら、String
を_Seq[Char]
_として表示できるラッパー。両者の違いがよくわかりません。mutable.IndexedSeq
_ mutable.GenericArray
_-Seq
ベースの配列のような構造。 「クラス」Array
はJavaのArray
であり、クラスよりもメモリストレージメソッドであることに注意してください。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(先入れ先出し)操作に最適化されたデータ構造。mutable.QueueProxy
_-_mutable.Queue
_のProxy
。SeqProxy
、SeqView
、SeqForwarder
immutable.Seq
_ immutable.Queue
_-FIFO最適化(先入れ先出し)データ構造を実装するクラス。 mutable
とimmutable
の両方のキューに共通のスーパークラスはありません。immutable.Stack
_-LIFOに最適化された(後入れ先出し)データ構造を実装するクラス。 mutable
immutable
スタックの両方に共通のスーパークラスはありません。immutable.Vector
_-?scala.xml.NodeSeq
_-_immutable.Seq
_を拡張する特殊なXMLクラス。immutable.IndexedSeq
_-上記のとおり。immutable.LinearSeq
_-上記のとおり。mutable.ArrayStack
_-配列を使用してLIFO最適化データ構造を実装するクラス。おそらく、通常のスタックよりも大幅に高速です。mutable.Stack
_、_mutable.SynchronizedStack
_-LIFOに最適化されたデータ構造を実装するクラス。mutable.StackProxy
_-_mutable.Stack
_のProxy
..mutable.Seq
_ mutable.Buffer
_-新しいメンバーの追加、前置、または挿入によって変更できる一連の要素。mutable.ArrayBuffer
_-_mutable.Buffer
_クラスの実装で、追加、更新、ランダムアクセス操作の償却時間が一定です。 NodeBuffer
など、いくつかの特殊なサブクラスがあります。mutable.BufferProxy
_、_mutable.SynchronizedBuffer
_。mutable.ListBuffer
_-リストに基づくバッファ。それは一定時間の追加とプリペンドを提供し、他のほとんどの操作は線形です。mutable.ObservableBuffer
_-A mixinトレイトは、Buffer
と混合すると、Publisher
インターフェイスを介して通知イベントを提供します。mutable.IndexedSeq
_-上記のとおり。mutable.LinearSeq
_-上記のとおり。Set
-セットは、多くても1つのオブジェクトを含むコレクションです。BitSet
-ビットセットとして保存される整数のセット。immutable.BitSet
_mutable.BitSet
_SortedSet
-要素が順序付けられているセット。immutable.SortedSet
_ immutable.TreeSet
_-ツリーに基づくSortedSet
の実装。SetProxy
-Proxy
のSet
。immutable.Set
_ immutable.HashSet
_-要素のハッシュに基づくSet
の実装。immutable.ListSet
_-リストに基づくSet
の実装。immutable.SetProxy
_-不変のProxy
のSet
。mutable.Set
_ mutable.HashSet
_-要素のハッシュに基づくSet
の実装。mutable.ImmutableSetAdaptor
_-不変のSet
から変更可能なSet
を実装するクラス。LinkedHashSet
-リストに基づくSet
の実装。ObservableSet
-A mixinトレイトは、Set
と混合すると、Publisher
インターフェイスを介して通知イベントを提供します。SetProxy
-Proxy
のSet
。SynchronizedSet
-A mixinトレイトは、Set
と混合すると、Publisher
インターフェイスを介して通知イベントを提供します。これは、コードを最大限に再利用するために行われました。特定の構造(トラバーサブル、マップなど)を持つクラスの具体的なgeneric実装は、Likeクラスで行われます。一般的な消費を目的としたクラスは、最適化できる選択されたメソッドをオーバーライドします。
クラスのビルダー、つまり、map
のようなメソッドで使用できる方法でそのクラスのインスタンスを作成する方法を知っているオブジェクトは、コンパニオンオブジェクトのメソッドによって作成されます。したがって、タイプXのオブジェクトを構築するには、Xのコンパニオンオブジェクトからそのビルダーを取得する必要があります。残念ながら、Scalaでは、クラスXからオブジェクトXに取得する方法がありません。そのため、 Xの各インスタンスで定義されたメソッドcompanion
。これは、クラスXのコンパニオンオブジェクトを返します。
通常のプログラムではこのような方法がいくらか使用される可能性がありますが、その目的は、コレクションライブラリでコードを再利用できるようにすることです。
あなたはそれを気にする必要はありません。これらは暗黙的に行われるため、どのように機能させるかを理解する必要はありません。
これらの暗黙は、コレクションのメソッドを親クラスで定義できるようにするために存在しますが、同じタイプのコレクションを返します。たとえば、map
メソッドはTraversableLike
で定義されていますが、List
で使用すると、List
が返されます。