タプルなどの単一のオブジェクトを保持するケースクラスを定義したい場合は、簡単に実行できます。
sealed case class A(x: (Int, Int))
この場合、「x」値の取得には一定の短い時間がかかり、このクラスは作成方法に関係なく、一定の小さなスペースしか必要としません。
さて、代わりに一連の値を保持したいとしましょう。次のようにできます。
sealed final case class A(x: Seq[Int])
これは以前と同じように機能するように見えるかもしれませんが、x のすべてを読み取るストレージと時間が x.length に比例するようになりました。
ただし、誰かが次のようなことを行う可能性があるため、これは実際には当てはまりません。
val hugeList = (1 to 1000000000).toList
val a = A(hugeList.view.filter(_ == 500000000))
この場合、a オブジェクトは単一の int をシーケンスに保持する無害なケース クラスのように見えますが、実際には数ギガバイトのメモリが必要であり、毎回その単一の要素にアクセスするのに数秒かかります。
これは、Seq[T] の代わりに List[T] のようなものをタイプとして指定することで修正できます。ただし、これは特定の実装への参照を追加するため見苦しく見えますが、実際には、Vector[T] などの他の適切に動作する実装も同様です。
もう 1 つの懸念される問題は、変更可能な Seq[T] を渡すことができることです。そのため、少なくとも scala.collection.Seq の代わりに immutable.Seq を使用する必要があるようです (ただし、現時点では、コンパイラーは実際に不変性を強制することはできません)。
ほとんどのライブラリを見ると scala.collection.Seq[T] を使用するのが一般的なパターンのようですが、これは本当に良い考えですか?
あるいは、Seq が型付けが最も短いという理由だけで使用されているのではないでしょうか。
編集で追加された新しいテキスト
クラス ライブラリを見ると、scala.reflect.api.Trees のような最もコアな機能のいくつかは実際に List[T] を使用しており、一般的に具象クラスを使用することは良い考えのようです。
しかし、なぜベクトルではなくリストを使用するのでしょうか?
ベクトルの長さは O(1)/O(log(n)) で、prepend、append、およびランダム アクセスであり、漸近的に小さく (リストは vtable と次のポインターにより ~3 ~ 4 倍大きくなります)、キャッシュ効率の高い並列計算をサポートします。 、一方 List には O(1) prepend 以外のプロパティはありません。
したがって、個人的には、Vector[T] がライブラリのデータ構造で公開されているものに対して正しい選択であることに傾いています。ライブラリのユーザーが必要とする操作がわからない場合、あまり人気がないように見えます。