5

2 つのリストaとが与えられた場合、とbの違いは何ですか? これらの演算子の 1 つが単に他の演算子を呼び出すのではないかと思いましたが、実際には、実装は完全に異なっているように見えます。a ::: ba ++ b

def :::[B >: A](prefix: List[B]): List[B] =
  if (isEmpty) prefix
  else if (prefix.isEmpty) this
  else (new ListBuffer[B] ++= prefix).prependToList(this)

override def ++[B >: A, That](that: GenTraversableOnce[B])
                      (implicit bf: CanBuildFrom[List[A], B, That]): That = {
  val b = bf(this)
  if (b.isInstanceOf[ListBuffer[_]])(this ::: that.seq.toList).asInstanceOf[That]
  else super.++(that)
}

使用の観点から、どちらを優先する必要がありますa ::: ba ++ b? 実装の観点から、これらの演算子の 1 つが単に他の演算子を呼び出さない特定の理由はありますか?

4

1 に答える 1

11

違いは、:::2 つのリストでのみ使用できることです。この操作は、Listデータ型でのみ使用できます。リストはシーケンスであるため、リストの連結演算子として機能します。

この++方法はより一般的で、任意の 2 つのコレクションの結合を作成できます。2 つのセットの場合はユニオンとして機能し、2 つのシーケンスの場合は連結として機能します。

++:::for 2:::のリストの間に意味的な違いはありません++

if実装で見られるステートメント++は最適化です。コレクションとコレクションの両方がthisリストthatの場合、リスト連結演算子を使用し:::て 2 つのリストを一緒に追加します。それ以外の場合は、とコレクション のすべての要素を type の適切なビルダーに++追加する の汎用実装を使用します。thisthatThat

したがって、リストに関連する違いはパフォーマンスです。機能リストの場合、一般的な++実装のように 2 番目のリストをトラバースする必要はありません。最初のリストのノードのみを再インスタンス化して、新しい機能リストを作成する必要があります。

于 2013-04-11T12:17:03.123 に答える