不确定。Go 语言规范明确不保证 map 的遍历顺序,且运行时会故意随机化每次 for range 的起点 bucket 和偏移,防止开发者依赖任何隐式顺序。
这样设计的原因:map 底层是哈希表(hmap + bmap 桶数组),元素位置由哈希值决定,还会随扩容发生渐进式搬迁,物理顺序本就无意义。强制随机化是一种防御性设计,把'无序'这个约束显性化,避免程序在旧版本上偶然正确、升级后出错。另外 map 并发读写会触发 fatal error(不是 panic,不可 recover),常与遍历问题一起被问到。
需要有序遍历时的做法:取出 key 排序后再访问。
keys := make([]string, 0, len(m))
for k := range m {
keys = append(keys, k)
}
sort.Strings(keys)
for _, k := range keys {
fmt.Println(k, m[k])
}
追问方向:map 的扩容机制、为什么不能对 map 元素取地址。