slice:动态数组视图
Go 的 slice 是对 底层数组 的引用。理解 slice 是后端面试必考点,与 Week 1 数组复杂度理论直接对应。
a := []int{1, 2, 3}
b := a[1:3] // len=2, cap=2, 共享底层
b[0] = 99 // a 变为 [1, 99, 3]
截取:s[low:high:max] 三索引形式可限制 cap,避免 append 覆盖意外区域。
append 与扩容
s := make([]int, 0, 4)
s = append(s, 1, 2, 3)
s2 := append(s, 4) // 可能仍用原数组
s3 := append(s, 5) // 若 cap 满,新数组,s 不变
面试说明:扩容后 新 slice 可能与旧 slice 脱钩;大 slice append 注意预分配 make([]T, 0, n) 减少拷贝。
常见陷阱
for _, v := range s { ptrs = append(ptrs, &v) } 全指向同一变量。var s []int 与 s := []int{} JSON 序列化行为不同。s = append(s[:i], s[i+1:]...) 不释放内存,大 buffer 可 copy 到新 slice。map internals(概念)
map 是哈希表:桶 + 溢出链。键可比较(==),无序 遍历顺序随机。
m := make(map[string]int, 100) // 预容量减少 rehash
v, ok := m["key"] // ok 表示是否存在
delete(m, "key")
零值 map 不能写:var m map[string]int; m["a"]=1 panic,需 make。
并发安全
- 普通 map:非线程安全。
sync.Map:读多写少、键稳定场景;否则RWMutex+ map。- 只读 map 初始化后多 goroutine 读:需保证无写(或 immutable copy)。
slice 与 map 面试题
- 如何用 slice 实现栈/队列?
- map 键能否是 slice?不能,slice 不可比较。
- 遍历 map 删除:先收集 key 再删,或 range 中 break 策略。
与算法联系
两数之和、前缀和在 Go 里用 map[int]int。Week 2 并发篇 week02-go-goroutine-channel 会讲多个 goroutine 写 map 的正确模式。
实践
读 reflect.SliceHeader 概念(Go 1.20+ 不推荐滥用 unsafe)。写小 benchmark 对比预分配 vs 默认 append。结合 /chapters/algorithm-lab 用 Go 刷 2 道哈希题。
实战巩固与面试表达
本篇属于 8 周冲刺 week02-go-slice-map 主题。复习时先闭卷回答 frontmatter 中三张 flashcard,再展开口述两个「为什么」:为什么这种方案能 work、边界失败时如何降级。与相邻章节对照:算法篇强调复杂度与模板,Go 篇强调工程默认写法,中间件篇强调线上故障案例。
动手与自检清单
用 25 分钟限时做 1 道相关练习题或画出一张架构/数据结构示意图;用 5 分钟写 STAR 片段说明你在项目里是否用过类似技术。记录 3 个面试追问及你的标准答法,存入 /zh/notebook/master-plan 笔记。若某点不熟,回到对应 /chapters 交互 Lab 重新走一遍流程,比死记卡片更有效。
易错点提醒
避免只背名词不会画图;避免只说优点不谈 trade-off(性能、一致性、运维成本至少提一项);避免把学习 Demo 说成百万 QPS 生产。回答时使用「场景 → 方案 → 结果 → 反思」四段式,体现工程成熟度。