在处理数据集合时,Go 提供了三种主要方式:数组(Array)、切片(Slice)和映射(Map)。其中,切片和映射是日常开发中使用频率最高的数据结构。本章将介绍它们的区别与用法。
示例代码
1package main
2
3import "fmt"
4
5func main() {
6 // 1. 数组 (Array)
7 // 长度是类型的一部分,固定不可变
8 var arr [3]int = [3]int{10, 20, 30}
9 fmt.Println("Array:", arr)
10
11 // 2. 切片 (Slice)
12 // 动态数组,引用类型
13 slice := []int{1, 2, 3, 4, 5}
14
15 // 操作:切取子集 [start:end] (左闭右开)
16 subSlice := slice[1:3] // 包含索引 1, 2 的元素 -> {2, 3}
17 fmt.Println("SubSlice:", subSlice)
18
19 // 操作:追加元素
20 // 当容量不足时,append 会自动扩容
21 slice = append(slice, 6)
22 fmt.Println("Appended Slice:", slice)
23
24 // 3. 映射 (Map)
25 // 键值对集合,类似 Python 的 dict 或 Java 的 HashMap
26 scores := make(map[string]int)
27 scores["Alice"] = 95
28 scores["Bob"] = 88
29
30 // 检查键是否存在
31 // val 是值,ok 是布尔值(存在为 true)
32 if score, ok := scores["Alice"]; ok {
33 fmt.Printf("Alice's score is %d\n", score)
34 }
35
36 // 删除键值对
37 delete(scores, "Bob")
38
39 // 遍历 Map (注意:遍历顺序是随机的)
40 for name, score := range scores {
41 fmt.Printf("%s: %d\n", name, score)
42 }
43}
关键点解释
数组 (Array)
- 声明:
[Length]Type。例如[5]int和[10]int是完全不同的类型。 - 数组是 值类型,赋值或传递给函数时会发生拷贝(复制整个数组)。一般很少直接使用。
切片 (Slice)
- 声明:
[]Type(不指定长度)。 - 切片本质上是对底层数组的一个“视窗”,包含三个属性:指针、长度 (
len)、容量 (cap)。 - 推荐:使用
make([]Type, len, cap)创建切片,或使用字面量[]Type{...}。 append函数可能会返回一个新的切片引用(当发生扩容时),所以必须重新赋值:s = append(s, val)。
映射 (Map)
- 声明:
map[KeyType]ValueType。 - 必须使用
make初始化,或者使用字面量。未初始化的 map 是nil,向其写入会导致 panic。 - Key 必须是支持比较(
==)的类型(如 int, string),切片不能作为 Key。 - 所有的 Map 操作都不是线程安全的(并发读写需要加锁)。
小结
- 数组长度固定,切片长度动态。优先使用切片。
- Map 处理键值对,查找速度快。
- 切片和 Map 都是引用类型,传递给函数时不会拷贝底层数据,效率高。
练习题
- 创建一个包含 10 个元素的整型切片,使用
range遍历并打印所有偶数。 - 统计一段英文文本中每个字符出现的次数,使用
map[rune]int存储并打印结果。