
在 Go 中,声明但未初始化的 map 是 nil 值,对其执行赋值操作(如 m[key] = value)会直接触发 runtime panic,无论 key 类型是基础类型、结构体还是嵌套 map。
在 go 中,声明但未初始化的 map 是 nil 值,对其执行赋值操作(如 `m[key] = value`)会直接触发 runtime panic,无论 key 类型是基础类型、结构体还是嵌套 map。
Go 的 map 是引用类型,但其零值为 nil —— 这意味着它不指向任何底层哈希表。与切片不同,map 的零值不可写入:任何试图通过 m[key] = value 向 nil map 写入数据的操作都会立即引发 panic: assignment to entry in nil map,哪怕 key 是结构体(如 COO{x: 0, y: 0})或 map 的层级看似“单层”。
在你的代码中:
var neighbours map[COO][]COO // ← 声明但未初始化,neighbours == nil
// ...
neighbours[COO{x: i, y: j}] = buds // ← 对 nil map 赋值 → panic!尽管 neighbours 是单层 map(key 为结构体,value 为切片),但因未调用 make() 初始化,其底层数据结构为空,Go 运行时拒绝任何写入操作。
✅ 正确做法:使用 make 显式初始化 map:
func main() {
neighbours := make(map[COO][]COO) // ✅ 推荐:短变量声明 + make
// 或:neighbours := make(map[COO][]COO, 600) // 可选预分配容量(约 30×20)
for i := 0; i < 30; i++ {
for j := 0; j < 20; j++ {
var buds []COO
if i < 29 {
buds = append(buds, COO{x: i + 1, y: j})
}
if i > 0 {
buds = append(buds, COO{x: i - 1, y: j})
}
if j < 19 {
buds = append(buds, COO{x: i, y: j + 1})
}
if j > 0 {
buds = append(buds, COO{x: i, y: j - 1})
}
neighbours[COO{x: i, y: j}] = buds // ✅ 现在安全
}
}
fmt.Println(len(neighbours)) // 输出 600
}⚠️ 注意事项:
- var m map[K]V 仅声明,不分配内存;必须 m = make(map[K]V) 或 m := make(map[K]V) 才可写入;
- make(map[K]V, n) 的第二个参数是提示容量(hint),非强制大小,但合理预估可减少扩容开销;
- 结构体作为 map key 时,需满足可比较性(字段均为可比较类型)——你定义的 COO 完全符合要求(int 可比较),无需额外实现 Equal 方法;
- 若需检查 map 是否已初始化,可用 if neighbours == nil,但更推荐“始终显式初始化”,避免条件分支引入不确定性。
总结:Go 中 所有 map 在使用前都必须 make 初始化,这是语言设计的明确约定,而非仅针对嵌套 map 或特殊 key 类型的例外规则。养成 := make(...) 的初始化习惯,是写出健壮 Go 代码的第一步。

















