Skip to main content

第 3 章:数组、切片与映射

本章目标​

  • 声明和遍历固定长度的数组
  • 使用切片保存长度可变化的数据
  • 理解切片的长度、容量和底层数组
  • 使用 append、copy 和切片表达式
  • 使用 map 保存键值对并完成增删改查
  • 使用 range 遍历集合

数组​

数组的长度是类型的一部分,创建后不能改变:

numbers := [3]int{10, 20, 30}
fmt.Println(len(numbers)) // 3

[3]int 和 [4]int 是两种不同的类型。使用 ... 可以让编译器根据元素数量推断长度:

levels := [...]string{"初级", "中级", "高级"}

数组赋值会复制全部元素:

copied := numbers
copied[0] = 100
// numbers[0] 仍然是 10

切片​

[]int 是切片,不是固定长度数组。切片可以通过 append 增长:

numbers := []int{10, 20, 30}
numbers = append(numbers, 40)

切片有长度和容量:

numbers := make([]int, 3, 5)
fmt.Println(len(numbers)) // 3
fmt.Println(cap(numbers)) // 5

len 表示当前元素数量,cap 表示底层数组从切片起始位置算起的容量。超过容量继续 append 时,Go 会自动分配新的底层数组。

切片表达式和 copy​

切片范围是左闭右开:

numbers := []int{10, 20, 30}
part := numbers[0:2]
fmt.Println(part) // [10 20]

numbers[0:2] 包含索引 0 和 1,不包含索引 2。常见简写:

numbers[:2] // numbers[0:2]
numbers[1:] // 从索引 1 到末尾
numbers[:] // 全部元素

切片通常与底层数组共享数据:

numbers := []int{10, 20, 30}
part := numbers[0:2]
part[0] = 100
// numbers 也会变成 [100 20 30]

需要独立副本时使用 copy:

independent := make([]int, len(part))
copy(independent, part)

映射 map​

map 用键查找值,类似 Java 的 Map:

ages := map[string]int{
"小明": 20,
"小红": 19,
}

ages["小刚"] = 21 // 添加
ages["小明"] = 22 // 修改
delete(ages, "小刚") // 删除

查询时可以使用第二个布尔值判断键是否存在:

age, exists := ages["小李"]
if !exists {
fmt.Println("没有找到这个人")
}

即使键不存在,age 也会得到 int 的零值,因此 exists 很重要。

range 遍历​

colors := []string{"红", "绿", "蓝"}
for index, color := range colors {
fmt.Println(index, color)
}

不需要索引时使用 _:

for _, color := range colors {
fmt.Println(color)
}

map 的遍历顺序不固定,不应依赖输出顺序。

练习题​

  1. 创建 5 个整数的数组,计算总和、平均值、最大值和最小值。
  2. 编写 reverse(numbers []int) 原地反转切片。
  3. 根据索引删除切片元素,处理无效索引。
  4. 使用 map 对整数切片去重并保持原顺序。
  5. 使用 map[string]int 统计单词出现次数。
  6. 使用 map[string]string 实现通讯录增删改查。
  7. 使用 map[string][]int 保存学生成绩并计算平均分。
  8. 使用 map 实现两数之和查找。

示例代码位于 E:\Project\Golang-Start\chapter-03-collections\examples。