我在许多例子中看到,有时使用Seq,而其他时候使用List……

除了前者是Scala类型,而List来自Java之外,还有什么区别吗?


在Scala中,List继承了Seq,但实现了Product;下面是List的正确定义:

sealed abstract class List[+A] extends AbstractSeq[A] with Product with ...

[注意:实际的定义稍微复杂一点,为了适应并利用Scala非常强大的集合框架。]


在Java术语中,Scala的Seq就是Java的List, Scala的List就是Java的LinkedList。

请注意,Seq是一个特性,它类似于Java的接口,但与正在崛起的防御方法相当。Scala的List是一个抽象类,由Nil和::扩展,它们是List的具体实现。

所以,Java的List是一个接口,而Scala的List是一个实现。

除此之外,Scala的List是不可变的,这与LinkedList不同。事实上,Java没有与不可变集合等价的东西(只读的东西只能保证新对象不能被更改,但您仍然可以更改旧对象,因此,“只读”的对象也可以更改)。

Scala的List通过编译器和库进行了高度优化,它是函数式编程中的基本数据类型。但是,它有局限性,对于并行编程是不够的。如今,Vector是比List更好的选择,但习惯很难改掉。

Seq是序列的一个很好的泛化,所以如果你为接口编程,你应该使用它。请注意,实际上有三个:集合。Seq, collection。mutable。Seq和collection。immutable。Seq,而后者是导入作用域的“默认”。

还有GenSeq和ParSeq。后一种方法在可能的情况下并行运行,而前者是Seq和ParSeq的父方法,适用于不考虑代码并行性的情况。它们都相对较新,所以人们不怎么使用它们。


Seq是一个具有定义的元素顺序的Iterable。序列提供了apply()方法用于索引,范围从0到序列的长度。Seq有很多子类,包括Queue、Range、List、Stack和LinkedList。

List是实现为不可变链表的Seq。它最好用于后进先出(LIFO)访问模式的情况。

下面是Scala FAQ中完整的集合类层次结构:


Seq是List实现的一个特性。

如果将容器定义为Seq,则可以使用任何实现Seq特性的容器。

scala> def sumUp(s: Seq[Int]): Int = { s.sum }
sumUp: (s: Seq[Int])Int

scala> sumUp(List(1,2,3))
res41: Int = 6

scala> sumUp(Vector(1,2,3))
res42: Int = 6

scala> sumUp(Seq(1,2,3))
res44: Int = 6

请注意,

scala> val a = Seq(1,2,3)
a: Seq[Int] = List(1, 2, 3)

只是简称:

scala> val a: Seq[Int] = List(1,2,3)
a: Seq[Int] = List(1, 2, 3)

如果未指定容器类型,则底层数据结构默认为List。


正如@daniel-c-sobral所说,List扩展了trait Seq,是一个由scala.collection.immutable实现的抽象类。$colon$colon(或简称::),但抛开技术细节不考虑,请注意,我们使用的大多数列表和Seq都是以Seq(1,2,3)或List(1,2,3)的形式初始化的,它们都返回scala.collection.immutable。$冒号,因此可以这样写:

var x: scala.collection.immutable.$colon$colon[Int] = null
x = Seq(1, 2, 3).asInstanceOf[scala.collection.immutable.$colon$colon[Int]]
x = List(1, 2, 3).asInstanceOf[scala.collection.immutable.$colon$colon[Int]]

因此,我认为唯一重要的是你想要公开的方法,例如,你可以使用::from List,我发现+:from Seq是多余的,我个人默认坚持使用Seq。