1. 简介
Scala 提供了一个非常丰富的集合库,位于 scala.collection
包下。
本篇文章将快速带你了解 Scala 中常用的集合类型及其使用方式。
2. Scala 集合的类型
Scala 的集合分为 可变(mutable)和不可变(immutable) 两种类型。我们先来看看它们的区别。
2.1. 可变集合(Mutable Collections)
可变集合在操作时会 原地更新或扩展,这意味着我们可以在不创建新集合的情况下添加、修改或删除元素 —— 这些操作会产生副作用。
所有可变集合类都定义在 scala.collection.mutable
包中。
2.2. 不可变集合(Immutable Collections)
不可变集合定义在 scala.collection.immutable
包中。
我们仍然可以对这些集合执行添加、删除或更新操作,但每次操作都会返回一个新的集合,原集合保持不变。
3. Scala 集合体系结构概览
Scala 的集合类继承体系以 Traversable
和 Iterable
两个特质为起点,进一步分为三个主要类别:List
、Set
和 Map
。
✅ Traversable
是所有集合的基特质,提供了 foreach
方法用于遍历整个集合。
✅ Iterable
是 Traversable
的子特质,定义了迭代器,可以逐个访问集合中的元素。
使用迭代器时,集合只能被遍历一次,因为每个元素在遍历过程中都会被处理。
接下来,我们重点介绍一些常用的不可变集合。
4. 常用的 Scala 集合类型
4.1. List
Scala 的 List
内部实现为一个 不可变的链表。
它保持元素插入顺序,且允许重复元素。适用于后进先出(LIFO)的操作场景,类似栈结构。
✅ List
实现了尾部结构共享(structural sharing),这意味着许多操作要么内存占用恒定,要么几乎不占用额外内存。
- 头部插入(prepend)和访问 head/tail 是 O(1)
- 其他操作如
length
、append
、reverse
以及按索引查找元素都是 O(n)
示例:
val numbersList: List[Int] = List(1, 2, 3, 4)
val emptyList: List[Int] = List() // 空列表
✅ List
由两个 case class 实现:scala.Nil
和 scala.::
,分别代表空列表和非空列表的构造。
val numbersList: List[Int] = 1 :: 2 :: 3 :: 4 :: Nil
val emptyList: List[Int] = Nil
val x :: xs = numbersList
assert(x == 1) // true
assert(xs == List(2, 3, 4)) // true
基本操作:
方法 | 说明 |
---|---|
head |
返回列表的第一个元素 |
tail |
返回除第一个元素外的其余元素组成的列表 |
isEmpty |
判断列表是否为空 |
示例:
val numbersList: List[Int] = 1 :: 2 :: 3 :: 4 :: Nil
assert(numbersList.head == 1) // true
assert(numbersList.tail == List(2, 3, 4)) // true
assert(numbersList.isEmpty == false) // true
常用方法:
List(1,2) ::: List(3,4) // List(1, 2, 3, 4) 拼接
List.fill(3)(100) // List(100, 100, 100) 创建相同元素的列表
List(1,2,3,4).reverse // List(4, 3, 2, 1) 反转
更多方法可参考:ScalaDoc List
4.2. Set
Scala 的 Set
表示一组 不重复的元素。
默认情况下,Scala 使用的是不可变集合。
val emptySet: Set[Int] = Set() // 空 Set
val numbersSet: Set[Int] = Set(1, 2, 3, 4)
如果需要使用可变版本,需要显式导入:
val mutableSet = collection.mutable.Set(1, 2, 3)
常用方法:
方法 | 说明 |
---|---|
head |
返回 Set 中的一个元素 |
tail |
返回除 head 外的其余元素 |
isEmpty |
判断 Set 是否为空 |
示例:
Set(1, 2, 3, 4).head // 1
Set(1, 2, 3, 4).tail // Set(2, 3, 4)
Set(1, 2, 3, 4).isEmpty // false
更多方法参考:ScalaDoc Set
4.3. Map
Map
是一组键值对的集合,键唯一。Scala 同样提供可变和不可变两种版本,默认导入的是不可变版本。
val immutableMap = Map(1 -> "a", 2 -> "b")
val mutableMap = collection.mutable.Map(1 -> "a", 2 -> "b")
常用方法:
方法 | 说明 |
---|---|
keys |
返回所有键组成的集合 |
values |
返回所有值组成的集合 |
isEmpty |
判断 Map 是否为空 |
示例:
Map(1 -> "a", 2 -> "b").keys // Set(1, 2)
Map(1 -> "a", 2 -> "b").values // Iterable("a", "b")
Map(1 -> "a", 2 -> "b").isEmpty // false
get
方法说明:
def get(key: K): Option[V]
- 如果键存在,返回
Some(value)
- 如果不存在,返回
None
Map(1 -> "a", 2 -> "b").get(1) // Some("a")
Map(1 -> "a", 2 -> "b").get(3) // None
更多方法参考:ScalaDoc Map
4.4. Tuple
Tuple
是一种可以将不同类型的数据组合在一起的容器。
Scala 2.x 提供了 Tuple2
到 Tuple22
,即最多支持 22 个元素的元组。
val t1 = (1, "A") // 等价于 Tuple2(1, "A")
访问方式:
val tuple3 = (1, "One", "A")
tuple3._1 // 1
tuple3._2 // One
tuple3._3 // A
或者使用模式匹配:
val (num, word, char) = (1, "One", 'A')
num // 1
word // "One"
char // 'A'
遍历元组:
val tuple = (1,2,3,4)
tuple.productIterator.foreach(println)
输出:
1
2
3
4
⚠️ 注意:Scala 2.x 的 Tuple
并不是集合类,不继承 Iterable
特质。
5. ArrayBuffer
ArrayBuffer
是 Scala 标准库提供的 可变集合,支持动态扩容、高效增删、以及通过索引访问。
虽然不如 List
、Map
、Set
那么常用,但功能强大,值得掌握。
创建与使用:
val buffer = ArrayBuffer.empty[Int]
buffer += 1
buffer += 2
buffer += 3
验证操作结果:
buffer should have size 3
buffer(0) shouldEqual 1
buffer(1) shouldEqual 2
buffer(2) shouldEqual 3
修改元素:
buffer(1) = 5
buffer shouldEqual ArrayBuffer(1, 5, 3)
删除元素:
val buffer = ArrayBuffer(1, 2, 3)
buffer -= 2
buffer shouldEqual ArrayBuffer(1, 3)
越界访问:
val buffer = ArrayBuffer(1, 2, 3)
assertThrows[IndexOutOfBoundsException] {
buffer(5)
}
6. 总结
本文我们简要介绍了 Scala 集合库的基本结构,对比了可变与不可变集合的差异,并详细讲解了 List
、Set
、Map
、Tuple
和 ArrayBuffer
的使用方式。
完整代码可参考:GitHub 项目地址 ✅