ChatGPT解决这个技术问题 Extra ChatGPT

Scala 中 Seq 和 List 的区别

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

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


C
Community

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

请注意,Seq 是一个 trait,它等效于 Java 的 interface,但等效于新兴的防御者方法。 Scala 的 List 是一个抽象类,由 Nil:: 扩展,它们是 List 的具体实现。

因此,Java 的 List 是一个 interface,Scala 的 List 是一个实现。

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

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

Seq 是对序列的一个很好的概括,所以如果你编程到接口,你应该使用它。请注意,它们实际上有三个:collection.Seqcollection.mutable.Seqcollection.immutable.Seq,而后者是导入范围的“默认”。

还有 GenSeqParSeq。后一种方法在可能的情况下并行运行,而前一种方法是 SeqParSeq 的父类,当代码的并行性无关紧要时,这是一个合适的概括。它们都是相对较新引入的,因此人们还没有太多使用它们。


RE “Java 没有不可变集合的等价物”,虽然 String 不是集合,但它是 Java 程序员熟悉的不可变类的示例。
@huynhjl 这不是重点。我在 Java 中存在的内容和 Scala 中存在的内容之间进行了比较,而 Java 中没有任何可变/不可变集合的概念。
Java 实际上具有不可变集合的等价物。它不是那么“宣传得很好”,但它在那里,当您大量使用泛型时,您可能会因此而打一些 UnsupportedOperationException。要在 Java 中创建不可变列表,您可以使用 Collections.unmodifiableList(),同样还有其他方法用于 Set、Map 等。docs.oracle.com/javase/6/docs/api/java/util/…
@jbx 不正确。如果你使用这些方法,你会得到一个对象,它会在修改它的方法上抛出异常,但不是一个不可变对象。如果原始对象在不可修改对象创建后被修改,不可修改对象将反映这一点。所以,不可修改,是的,不可变的,不。
@jbx接收方法不能保留对它接收到的集合的引用并假设它永远不会改变,并且标准Java库中没有类型可以保证 - 那是不变性。因此,例如,该接收方法不能保证线程安全。这甚至没有触及由不变性启用的持久性特征。没有这一切,它就不能被称为“等效”。
C
Ceasar Bautista

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

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

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

https://i.stack.imgur.com/2fjoA.png


Array(和 ArrayBuffer)在哪里?它不是一种可迭代的
This answer 显示数组
如果您对肯定的最好在具有后进先出 (LIFO) 访问模式的情况下使用感到好奇,请考虑使用 prepend()head() 操作作为 O(1) vs append() OR last(),这是列表中元素数量的 O(n)。
A
Akavall

SeqList 实现的特征。

如果您将容器定义为 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


T
Thomas Grainger

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

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

[注意:the actual definition 稍微复杂一点,以适应和利用 Scala 非常强大的集合框架。]


P
Profiterole

正如@daniel-c-sobral 所说,List 扩展了 trait Seq 并且是由 scala.collection.immutable.$colon$colon(或简称为 ::)实现的抽象类,但撇开技术问题不谈,请注意,我们使用的大多数列表和 seq 都是在Seq(1, 2, 3)List(1, 2, 3) 的形式都返回 scala.collection.immutable.$colon$colon,因此可以写:

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]]

结果,我认为唯一重要的是您要公开的方法,例如,在您可以使用 List 中的 :: 之前,我认为 Seq 中的 +: 是多余的,我个人坚持使用 Seq默认。