第 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 的遍历顺序不固定,不应依赖输出顺序。
练习题
- 创建 5 个整数的数组,计算总和、平均值、最大值和最小值。
- 编写
reverse(numbers []int)原地反转切片。 - 根据索引删除切片元素,处理无效索引。
- 使用
map对整数切片去重并保持原顺序。 - 使用
map[string]int统计单词出现次数。 - 使用
map[string]string实现通讯录增删改查。 - 使用
map[string][]int保存学生成绩并计算平均分。 - 使用
map实现两数之和查找。
示例代码位于 E:\Project\Golang-Start\chapter-03-collections\examples。