55

特定の関数の戻り型をSeqvsvsIterableとして(または、階層Traversable内でさらに深く)入力することを選択するのはいつですか?Seq

どのようにその決定を下しますか?デフォルトでsを返すコードがたくさんありSeqます(通常はDBクエリと連続した変換の結果から始まります)。Traversable私はデフォルトで、そしてSeq特定の注文を特に期待するときにリターンタイプを作りたいと思う傾向があります。しかし、そうすることには強い正当性がありません。

私は各特性の定義に完全に精通しているので、用語を定義することで答えないでください。

4

5 に答える 5

43

これは良い質問です。2つの懸念のバランスを取る必要があります。

  • (1)後で実装を変更できるように、APIを一般的に保つようにしてください
  • (2)コレクションに対して実行するいくつかの便利な操作を呼び出し元に提供します

ここで、(1)はタイプについて少し具体的にするように求められ(たとえばIterable、over Seq)、(2)はその反対を求めます。

リターンタイプがちょうどIterableの場合でも、たとえば、を返すことができるVectorので、発信者が追加のパワーを取得したい場合は、コール.toSeqまたは.toIndexedSeqオンするだけで、その操作は。の場合は安価ですVector

バランスの尺度として、3番目のポイントを追加します。

  • (3)データの編成方法を反映したタイプを使用します。たとえば、データにシーケンスがあると想定できる場合は、を指定しますSeq。2つの等しいオブジェクトが発生しないと想定できる場合は、を指定しSetます。等。

これが私の経験則です:

  • コレクションの小さなセットのみを使用するようにしてください:Set、、、MapSeqIndexedSeq
  • Listただし、を優先して使用すると、この前のルールに違反することがよくありSeqます。これにより、呼び出し元は短所抽出機能を使用してパターンマッチングを行うことができます。
  • 不変型のみを使用する(例collection.immutable.Setcollection.immutable.IndexedSeq
  • 具体的な実装()を使用しないでください。ただし、同じAPIを提供するVector一般的なタイプ( )を使用してください。IndexedSeq
  • 可変構造をカプセル化し、インスタンスのみを返す場合、呼び出し元は、たとえばそれを呼び出すことIteratorによって、厳密な構造を簡単に生成できます。toList
  • APIが小さく、「ビッグデータスループット」に明確に調整されている場合は、IndexedSeq

もちろん、これは私の個人的な選択ですが、それが正気に聞こえることを願っています。

于 2012-07-28T17:09:57.787 に答える
9
  • Seqデフォルトでどこでも使用します。
  • IndexedSeqインデックスでアクセスする必要がある場合に使用します。
  • それ以外のものは、特別な状況でのみ使用してください。

これらは「常識的な」ガイドラインです。それらはシンプルで実用的であり、原則とパフォーマンスのバランスを取りながら、実際にうまく機能します。原則は次のとおりです。

  1. データがどのように編成されているかを反映するタイプを使用してください(OPとziggystarに感謝します)。
  2. メソッド引数と戻り型の両方でインターフェイス型を使用します。APIの入力タイプと戻りタイプの両方が、一般性の柔軟性の恩恵を受けています。

Seq両方の原則を満たします。http://docs.scala-lang.org/overviews/collections/seqs.htmlで説明されているように:

シーケンスは、[有限]の長さを持ち、要素が0から始まる固定のインデックス位置を持つ一種の反復可能です。

90%の確率で、データはSeqです。

その他の注意事項:

  • Listは実装タイプであるため、APIで使用しないでください。VectorたとえばList、変換を行わずにを使用することはできません。
  • Iterableを定義しませんlengthIterable有限のシーケンスと潜在的に無限のストリームにわたって抽象化します。ほとんどの場合、有限のシーケンスを処理しているため、「長さがあり」、それをSeq反映します。多くの場合、実際には長さを利用しません。しかし、それは十分な頻度で必要であり、提供するのは簡単なので、を使用してSeqください。

欠点:

これらの「常識的な」慣習には、いくつかのわずかな欠点があります。

  • Listconsパターンマッチングを使用することはできませんcase head :: tail => ...ここで説明されているように、を使用できます。ただし、重要なのは、Scala:パターンマッチングSeq[Nothing]で説明されているようにマッチングが機能することです。:++:Nil

脚注:

于 2015-05-01T21:38:15.847 に答える
5

メソッドの戻り型をできるだけ具体的にします。次に、発信者がそれをとして保持したい場合、SuperSpecializedHashMapまたはとして入力したい場合は、そうGenTraversableOnceすることができます。これが、コンパイラがデフォルトで最も具体的なタイプを推測する理由です。

于 2012-07-28T16:50:05.800 に答える
1

私が従う経験則は、実装に応じて、戻り型を可能な限り具体的にし、引数の型を可能な限り一般的にすることです。従うのは簡単なルールであり、タイププロパティの一貫した保証を最大限の自由度で提供します。

たとえば、またはのようなメソッドを使用してデータ構造をトラバースするだけの関数実装がある場合mapfilterまたはfold-トレイトに実装されているものであれば、任意のタイプの入力コレクションでTraversable同等に実行されることが期待できます- List、、、または、したがって、入力引数はとして指定する必要があります。関数の出力タイプの選択は、その実装にのみ依存する必要があります。この場合もそうする必要があります。ただし、関数でこのデータ構造を、、、などのメソッドを使用してより具体的なタイプに強制する場合は、適切なタイプを指定する必要があります。実装とリターンタイプの一貫性に注意してください。VectorHashSetHashMapTraversable[T]TraversabletoListtoSeqtoSet

関数がインデックスによって入力の要素にアクセスする場合、入力はとして指定する必要があります。IndexedSeqこれは、メソッドの効果的な実装を保証する最も一般的なタイプであるためですapply

抽象メンバーの場合、同じルールが適用されますが、実装ではなく使用方法に基づいて戻りタイプを指定する必要があるという唯一の違いがあります。したがって、ほとんどの場合、実装よりも一般的です。カテゴリの選択肢SeqSetまたはMap最も期待されています。

このルールに従うと、たとえば、アイテムがの代わりに追加されListたりcontains呼び出されたりする場合に、ボトルネックの非常に一般的なケースから身を守ることができますが、プログラムは自由度が高く、タイプの選択の意味で一貫しています。SeqSet

于 2012-07-30T11:09:06.070 に答える
0

クイックノート:Scala 2.13.xではTraversable、画像から外れています。 Iterableははるかに一般的であり、今後、二重性は正当化されないと判断されました。 Iterable現在、コレクション階層の最上位にあり、Traversable非推奨になっています。

于 2020-11-18T02:00:02.447 に答える