我在许多例子中看到,有时使用Seq,而其他时候使用List……
除了前者是Scala类型,而List来自Java之外,还有什么区别吗?
在Scala中,List继承自Seq,但实现了产品;下面是列表的正确定义:
sealed abstract class List[+A] extends AbstractSeq[A] with Product with ...
[注意:实际定义有点复杂,为了适应并利用Scala非常强大的集合框架。]
在Java术语中,Scala的Seq将是Java的List, Scala的List将是Java的LinkedList。
Seq
List
LinkedList
注意,Seq是一个trait,它等价于Java的interface,但具有等价于正在兴起的防御方法。Scala的List是一个抽象类,由Nil和::扩展而来,它们是List的具体实现。
trait
interface
Nil
::
因此,Java的List是一个interface,而Scala的List是一个实现。
除此之外,Scala的List是不可变的,这与LinkedList不同。事实上,Java没有与不可变集合等价的东西(只读的东西只能保证新对象不能被更改,但您仍然可以更改旧对象,因此,“只读”的对象也可以更改)。
Scala的List通过编译器和库进行了高度优化,它是函数式编程中的基本数据类型。但是,它有局限性,对于并行编程是不够的。如今,Vector是比List更好的选择,但习惯很难改掉。
Vector
Seq是序列的一个很好的泛化,所以如果你为接口编程,你应该使用它。注意,它们实际上有三个:collection.Seq, collection.mutable.Seq和collection.immutable.Seq,后者是导入作用域的“默认”。
collection.Seq
collection.mutable.Seq
collection.immutable.Seq
还有GenSeq和ParSeq。后一种方法在可能的情况下并行运行,而前者是Seq和ParSeq的父方法,适用于代码并行性不重要的情况。它们都是相对较新的产品,所以人们还不怎么使用。
GenSeq
ParSeq
Seq是一个Iterable,其元素顺序已定义。序列提供了一个方法apply()用于索引,范围从0到序列的长度。Seq有很多子类,包括Queue、Range、List、Stack和LinkedList。
apply()
列表是一个实现为不可变链表的Seq。它最好用于后进先出(LIFO)访问模式的情况。
下面是来自Scala常见问题解答的完整集合类层次结构:
Seq是List实现的trait。
如果将容器定义为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扩展了特征Seq,是一个由scala.collection.immutable.$colon$colon(或简称::)实现的抽象类,但抛开技术细节,请注意,我们使用的大多数列表和Seq都是以Seq(1, 2, 3)或List(1, 2, 3)的形式初始化的,它们都返回scala.collection.immutable.$colon$colon,因此可以这样写:
scala.collection.immutable.$colon$colon
Seq(1, 2, 3)
List(1, 2, 3)
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]]
因此,我认为唯一重要的是你想要公开的方法,例如,为了prepend,你可以使用List中的::,我发现它与Seq中的+:是多余的,我个人默认坚持使用Seq。
+: