在 Go 语言中,判断指针是否为空(即是否为 nil)是避免空指针异常的关键操作。以下是详细的方法和注意事项:
1. 基本语法:使用 == nil 判断
var ptr *int
if ptr == nil {
fmt.Println("指针为空")
} else {
fmt.Println("指针不为空")
}
- 原理:Go 中的指针变量未初始化时默认值为
nil,表示不指向任何内存地址。 - 适用场景:适用于所有指针类型(如
*int、*string、*struct{}等)。
2. 结构体指针的判断
type Product struct {
Name string
Price int
}
func main() {
var p *Product
if p == nil {
fmt.Println("结构体指针为空")
}
}
- 注意:结构体本身不能为
nil,只有结构体指针可以为nil。 - 对比:如果直接声明结构体变量(而非指针),其字段会自动初始化为零值,不能用
nil判断:var product Product if product == nil { // ❌ 编译错误:product 是结构体,不能与 nil 比较 // ... }
3. 函数参数中的指针判断
在函数中接收指针参数时,需先判断是否为 nil 再解引用:
func GetValue(ptr *int) int {
if ptr == nil {
return -1 // 返回默认值或错误码
}
return *ptr
}
- 关键点:避免直接解引用未检查的指针(如
*ptr),否则会导致运行时恐慌(panic)。
4. 错误示例与常见问题
❌ 错误 1:直接比较非指针类型与 nil
var name string
if name == nil { // ❌ 编译错误:string 类型不能与 nil 比较
// ...
}
- 修正:字符串应检查是否为空字符串:
if name == "" { // ... }
❌ 错误 2:忽略指针解引用前的检查
var ptr *int
fmt.Println(*ptr) // ❌ 运行时恐慌:nil 指针解引用
5. 高级场景:处理可能为 nil 的接口或函数返回值
✅ 正确做法:检查接口是否为 nil
var i interface{}
if i == nil {
fmt.Println("接口为空")
}
- 注意:接口为
nil的条件是动态类型和动态值都为nil。例如:var p *int var i interface{} = p if i == nil { // true,因为 p 是 nil // ... }
✅ 处理函数返回的指针
func NewUser() *User {
return nil // 可能返回 nil
}
user := NewUser()
if user == nil {
fmt.Println("用户不存在")
}
6. 避免空指针异常的最佳实践
-
始终检查指针是否为 nil:
if ptr != nil { // 安全地使用 *ptr } -
使用
defer和recover捕获异常(不推荐作为常规手段):defer func() { if r := recover(); r != nil { fmt.Println("捕获到空指针异常:", r) } }() -
返回错误码或默认值:
func SafeDereference(ptr *int) (int, error) { if ptr == nil { return 0, errors.New("指针为空") } return *ptr, nil }
总结
| 场景 | 判断方式 | 示例代码 |
|---|---|---|
| 普通指针 | ptr == nil | if ptr == nil { ... } |
| 结构体指针 | ptr == nil | if p == nil { ... } |
| 接口是否为 nil | i == nil | if i == nil { ... } |
| 字符串是否为空 | str == "" | if str == "" { ... } |
| 函数返回指针 | 先判断是否为 nil | if user == nil { ... } |
关键原则:
- 指针类型才能用
nil判断,非指针类型(如int、string)不能与nil比较。 - 解引用前必须检查是否为 nil,否则会导致运行时恐慌。
1029

被折叠的 条评论
为什么被折叠?



