外观
array 与 slice
Phase 01 — Go Fundamentals · 知识点 07 · 08
1. 学习目标
- 理解 array 固定长度、slice 动态长度
- 掌握 slice 的创建、追加、切片操作
- 理解 slice 底层是引用类型
- 知道何时用 array(很少)vs slice(几乎总是)
2. 为什么需要
后端要处理一组数据:多个 AGV 坐标、一批传感器读数、设备 ID 列表。Go 用 array 和 slice 表示同类型元素集合,但日常开发 99% 用 slice。
3. 核心概念
array — 固定长度
go
var coords [3]float64 = [3]float64{10.0, 20.0, 30.0}
// [3]float64 和 [5]float64 是不同类型!slice — 动态长度
go
ids := []string{"AGV-001", "AGV-002"}
ids = append(ids, "AGV-003")
sub := ids[0:2] // 切片 [start:end),左闭右开| 操作 | 说明 |
|---|---|
len(s) | 元素个数 |
cap(s) | 底层数组容量 |
append(s, x) | 追加元素,可能触发扩容 |
s[low:high] | 切片,共享底层数组 |
4. 基础语法
go
package main
import "fmt"
func main() {
// 创建 slice
speeds := make([]float64, 0, 10) // len=0, cap=10
speeds = append(speeds, 1.2, 0.8, 1.5)
// 遍历
for i, v := range speeds {
fmt.Printf("[%d] %.1f m/s\n", i, v)
}
// 只遍历值
for _, v := range speeds {
fmt.Println(v)
}
}5. 代码解析
make([]T, len, cap)预分配,减少 append 扩容次数append返回新 slice(可能指向新底层数组)- 切片
sub := s[1:3]与s共享底层数组,修改 sub 可能影响 s
6. JavaScript / TypeScript 对比
| Go slice | JS Array |
|---|---|
| 同类型元素 | 可混合类型 |
| 值语义+引用底层 | 引用对象 |
[start:end) 左闭右开 | slice(start, end) 类似 |
| 无 map/filter 链式 | 有丰富的数组方法 |
slice 只能类比 JS Array,底层机制并不相同。
7. 常见错误
- 对 nil slice append → 合法,会自动分配
- 切片共享底层导致意外修改 → 用
copy复制 - 混淆 array 和 slice 类型 →
[3]int≠[]int - range 循环中修改 slice 长度 → 行为需小心
8. 实际应用
go
// AGV 路径点
path := []struct{ X, Y float64 }{
{10, 5}, {20, 8}, {30, 12},
}
// 过滤超速 AGV
var overspeed []string
for _, agv := range agvs {
if agv.Speed > maxSpeed {
overspeed = append(overspeed, agv.ID)
}
}Three.js 前端接收的坐标数组,Go 后端用 []float64 或 []Position slice 组装 JSON。
9. 深入理解
slice 结构:pointer + len + cap。扩容策略通常翻倍,大数据量时用 make 预分配 cap 提升性能。
10. 练习
- L1:创建、append、遍历 slice
- L2:切片操作与 len/cap
- L3:copy 避免共享底层
- L4:管理 AGV 路径点 slice
11. 学习检查
- [ ] array 与 slice 类型区别?
- [ ] append 返回值为何要接收?
- [ ]
[start:end)边界规则?
12. 下一步
→ map:键值对存储设备状态