学会保存一组同类型数据,并使用上一课的循环遍历它们。按 main.go 中的 1~7 节逐段手敲,不急着学习复杂内存管理。
本课独立存放,共享根目录的 go.mod,仅使用标准库,无需安装第三方依赖。
scores := [3]int{80, 90, 75}
fmt.Println(scores[0]) // 第一个元素,值为 80。
scores[2] = 85 // 修改第三个元素。
[3]int 表示包含 3 个整数的数组,长度也是类型的一部分;[3]int 与 [4]int 是不同类型。0 开始,最后一个元素的索引是 len(scores)-1。var scores [3]int 不给初始值时,三个元素都为 0。与 C 类似,可以通过索引访问数组;但 Go 会做边界检查,而且数组赋值会复制整个数组。
for index, score := range scores {
fmt.Println(index, score)
}
index 是索引,score 是当前元素值的副本。只需要值时,写 for _, score := range scores。
修改 score 不会直接修改数组中的整数元素。要修改原元素,应通过索引,例如 scores[index] = score + 1。
numbers := []int{10, 20, 30}
numbers = append(numbers, 40, 50)
| 对比 | 数组 | 切片 |
|---|---|---|
| 类型示例 | [3]int |
[]int |
| 长度 | 固定,属于类型的一部分 | 运行时可变化,不属于类型的一部分 |
| 追加 | 不能直接 append | 使用 append 并接收返回值 |
| 赋值 | 复制整个数组 | 复制切片描述信息,可能共享底层数组 |
append 返回更新后的切片值,要写回变量。底层空间不足时可能分配新的数组,不要假设追加后原来的共享关系始终不变,也不要依赖固定的容量增长倍数。
middle := numbers[1:3]
范围是左闭右开:包含索引 1、2,不包含 3;因此长度是 3-1=2。
常见写法还有 numbers[:2](前两个元素)、numbers[2:](从索引 2 到末尾)、numbers[:](全部)。
截取得到的子切片不是独立副本,它与原切片共享底层数组。因此本课 middle[0] = 200 会修改 numbers[1]。
alias := numbers 也不是复制全部元素;修改 alias 中已有元素,可能影响 numbers。
backup := make([]int, len(numbers))
copied := copy(backup, numbers)
make 创建目标切片,copy 复制元素并返回实际复制数量,即两边长度的较小值。目标长度不够时,不会自动扩容。
本课元素是整数,所以这样能得到不共享元素存储的独立副本;将来元素包含切片或指针时,还需要理解浅拷贝。
var tasks []string 的零值为 nil,可以直接 append。len 是当前可访问的元素数量。cap 是从切片起点到底层数组末尾的容量,不是可直接使用索引访问的范围。cap 大于 len,也不能直接访问 slice[len(slice)],应先 append 或合法地重新切片。[]int{};长度为 0 并不一定表示 nil。在仓库根目录执行:
New-Item -ItemType Directory -Force bin/05_arrays_slices | Out-Null
go build -o ./bin/05_arrays_slices/arrays_slices.exe ./lessons/05_arrays_slices
.\bin\05_arrays_slices\arrays_slices.exe
修改源码后需要重新编译。快速编译并运行也可以用:
go run ./lessons/05_arrays_slices
或者从根目录进入本课,再执行 go run .:
Set-Location lessons/05_arrays_slices
go run .
=== 数组 ===
成绩:[80 90 75],长度:3
第一个成绩:80
修改后的成绩:[80 90 85]
=== 遍历与求和 ===
第 1 个成绩:80
第 2 个成绩:90
第 3 个成绩:85
总分:255,平均分:85.00
=== 切片与追加 ===
切片:[10 20 30 40 50],长度:5
=== 截取与共享 ===
numbers[1:3]:[20 30]
修改子切片后,原切片:[10 200 30 40 50]
=== 复制切片 ===
复制了 5 个元素,副本:[999 200 30 40 50]
原切片保持不变:[10 200 30 40 50]
=== 从空切片开始 ===
追加前:nil=true,长度=0,容量=0
任务:复习循环
任务:学习切片
=== 数组赋值是复制 ===
数组副本:[100 90 85],原数组:[80 90 85]
numbers 再追加两个整数,观察长度变化。numbers[:2],预测输出后再运行。tasks 追加第三个任务。if score >= 90,统计优秀成绩数量。特别注意:本例数组非空,可以计算平均值;未来处理空切片时,应先判断长度,避免除以零。
如果另外手敲一份,放进本课的 practice/ 子目录,用 go run ./lessons/05_arrays_slices/practice 运行,不要在同一个包中声明两个 main 函数。
下一课建议学 map,认识按“键”查找数据的方式。