在处理数据集合时,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 都是引用类型,传递给函数时不会拷贝底层数据,效率高。

练习题

  1. 创建一个包含 10 个元素的整型切片,使用 range 遍历并打印所有偶数。
  2. 统计一段英文文本中每个字符出现的次数,使用 map[rune]int 存储并打印结果。

相关阅读