
在 go 中,对 nil map 进行赋值会触发 runtime panic:“assignment to entry in nil map”。根本原因是方法接收者使用了值类型而非指针类型,导致 map 初始化操作作用于副本,原结构体字段仍为 nil。
在 go 中,对 nil map 进行赋值会触发 runtime panic:“assignment to entry in nil map”。根本原因是方法接收者使用了值类型而非指针类型,导致 map 初始化操作作用于副本,原结构体字段仍为 nil。
当你定义一个结构体并包含 map 字段(如 collection map[uint64]Object)时,该字段默认初始化为 nil。Go 不允许直接向 nil map 写入键值对——这会立即引发 panic。必须先通过 make() 显式初始化 map,才能安全使用。
但问题常出在初始化方式上。在你的代码中:
func (test Test) init() {
test.collection = make(map[uint64]Object)
}test 是值接收者,意味着 init() 接收的是 Test 的一份拷贝。test.collection = make(...) 仅修改了这个临时副本的字段,函数返回后,原始 *Test 实例中的 collection 仍为 nil。因此后续 test.collection[1] = ... 实际是在向 nil map 赋值,panic 不可避免。
✅ 正确做法:将接收者改为指针类型,确保修改作用于原始实例:
func (t *Test) Init() { // 建议首字母大写,符合导出方法命名规范
t.collection = make(map[uint64]Object)
}调用时保持不变:
test := &Test{}
test.Init() // ✅ 现在 collection 已正确初始化
test.collection[1] = &ObjectImpl{}⚠️ 更佳实践:采用 Go 社区推荐的构造函数模式(NewXXX)。它将初始化逻辑封装,避免用户误用未初始化的结构体:
type Test struct {
collection map[uint64]Object
}
// NewTest 返回已完全初始化的 *Test 实例
func NewTest() *Test {
return &Test{
collection: make(map[uint64]Object),
}
}
// 使用示例
func main() {
test := NewTest() // 无需手动调用 Init()
test.collection[1] = &ObjectImpl{}
}? 补充说明:
- 若 Test 需导出(即首字母大写),其字段 collection 也应小写(非导出),否则外部包可绕过初始化直接赋值 nil map;
- 方法名 init 与 Go 内置 init() 函数同名,易混淆,建议改用 Init() 或 Initialize();
- 所有 map 字段都应显式初始化(make),切勿依赖零值。
遵循指针接收者 + 构造函数模式,可彻底规避 “assignment to entry in nil map” panic,提升代码健壮性与可维护性。

















