[scala]なぜListではなくSeqを使うべきなのか

  • 79
    Like
  • 0
    Comment
More than 1 year has passed since last update.

Listは使わずにSeqにしなさいとよく言われるけど、何故そうなのかはいまいちよくわかってなかったので、調べました。基本的な内容です。

そもそもSeqとは

Seq(scala.collection.Seq)は、Iterableのうち順序を持つものを指します。
全てのcollectionはIterableであるので、順序がある(要素にindexでアクセスできる)コレクションは全てSeqです。(SeqでないコレクションにはMapやSetがあります)

Seqはscala.collection下にあるので、VectorだろうとMutableListだろうとSeqです。メソッドや関数の引数の型には、特別な理由がない限り、取りうる型の範囲を狭めてしまうListなどよりSeqを指定したほうが良さそうです。

scala> Seq
res0: scala.collection.Seq.type = scala.collection.Seq$@5680a178

scala> List
res1: scala.collection.immutable.List.type = scala.collection.immutable.List$@2d6a9952

IndexedSeqとLinearSeq

Seqは2種類のサブトレイトに分かれます。

  • IndexedSeq : 要素へのランダムアクセスとlengthが速い
  • LinearSeq : head/tailが速い

と、それぞれ異なるパフォーマンス特性を保証しています。

(immutableの方では)IndexedSeqのデフォルト実装はVectorであり、LinearSeqのデフォルト実装はListです。また、単純にSeqを作ったときもListが作成されます。
scala的にはindexアクセスはあまりしないでしょうから、SeqのデフォルトがLinearSeqなのは合理的と言えます。ちなみに、mutable.Seqはmutable.IndexedSeqと同じArrayBufferを作成します。

scala> Seq(1)
res2: Seq[Int] = List(1)

scala> IndexedSeq(1,2)
res3: IndexedSeq[Int] = Vector(1, 2)

基本的には「Listが使いたい」ことはあまりなくて、「先頭からのアクセスが速い配列が使いたい」ことのほうが多いとおもうので、scalaで配列的なものが使いたいときは、その使い方に応じてLinearSeq(Seq)かIndexedSeqを使うようにすれば良さそうです。

まとめ

  • 引数の型にはListよりSeqを使ったほうがいい
  • コンストラクタもListよりSeqを使ったほうがいい