Go 中声明指针变量(如 var p *string)默认初始化为 nil;直接对未初始化的 nil 指针解引用(如 *p = "x")将触发 panic;必须先让指针指向有效内存地址(如取变量地址或调用 new()),才能安全写入值。
go 中声明指针变量(如 `var p *string`)默认初始化为 `nil`;直接对未初始化的 nil 指针解引用(如 `*p = "x"`)将触发 panic;必须先让指针指向有效内存地址(如取变量地址或调用 `new()`),才能安全写入值。
在 Go 中,指针是显式且安全优先的设计:声明一个指针变量并不会自动为其分配底层存储空间,它仅是一个“地址容器”。理解这一点是避免运行时 panic 的关键。
指针的零值是 nil,不是可写内存
var b *string // b == nil,不指向任何有效内存 *b = "bar" // ❌ panic: invalid memory address or nil pointer dereference
此处 b 是 *string 类型,其零值为 nil。尝试通过 *b 写入,相当于向地址 0x0 写入数据——Go 运行时会立即中止程序并报错。
正确初始化指针的两种常用方式
✅ 方式一:指向已有变量(取地址)
var c string = "bar" b := &c // b 现在指向变量 c 的内存地址 *b = "world" // ✅ 合法:修改 c 的值 fmt.Println(c) // 输出 "world"
此时 b 和 c 共享同一块内存,对 *b 的修改即对 c 的修改。
✅ 方式二:动态分配新内存(new())
b := new(string) // 分配一个 *string,返回指向新分配零值字符串的指针 // 等价于:b := &""(但语义更清晰) *b = "bar" // ✅ 合法:写入新分配的内存 fmt.Println(*b) // 输出 "bar"
new(T) 会为类型 T 分配零值内存,并返回 *T。这是创建独立、可修改指针值的推荐方式之一。
对比两个示例的本质差异
- 第一个示例成功:b = &c 显式将 b 初始化为非-nil 地址,后续 *b = ... 才有意义;
- 第二个示例失败:跳过初始化,直接 *b = "bar",试图向 nil 地址写入,违反内存安全规则。
注意事项与最佳实践
- ⚠️ 永远不要解引用未初始化(nil)的指针;
- ✅ 使用 if b != nil 显式检查指针有效性(尤其在函数参数或结构体字段中);
- ✅ 优先使用 &variable 或 new(T) 初始化,避免裸声明后遗忘赋值;
- ? 若需延迟初始化,可结合 nil 检查与条件逻辑:
var b *string if b == nil { b = new(string) } *b = "initialized"
指针不是魔法——它是明确的内存引用。Go 强制你显式决定“指向哪里”,这正是其内存安全与可预测性的基石。











