go语言 *和
以链表的定义为例
type ListNode struct {Val intNext *ListNode
}
var pre *ListNode
和 pre := &ListNode{}
是两种不同的指针初始化方式,主要区别在于变量的声明方式、内存分配和初始值。
1. var pre *ListNode
行为特点
- 只声明指针变量,不分配内存
pre 是一个nil
指针,指向 ListNode 类型的零值(nil) - 未初始化结构体
直接访问pre.Val
或pre.Next
会导致panic: nil pointer dereference
示例
var pre *ListNode // pre == nil
fmt.Println(pre == nil) // 输出: true// 以下代码会 panic!
// pre.Val = 1 // 报错:解引用 nil 指针
适用场景
- 需要先声明指针,稍后通过 new 或取地址初始化时
- 作为函数参数,允许接收 nil 指针时
2. pre := &ListNode{}
行为特点
- 声明并初始化指针
使用 &ListNode{} 创建结构体实例,并返回其指针 - 分配内存,字段赋零值
结构体所有字段初始化为零值(Val: 0, Next: nil)
示例
pre := &ListNode{} // pre != nil
fmt.Println(pre == nil) // 输出: false
fmt.Println(pre.Val) // 输出: 0(int 零值)
fmt.Println(pre.Next) // 输出: nil(指针零值)// 安全赋值
pre.Val = 1 // 正常执行
适用场景
- 需要立即使用结构体指针,且避免 nil 解引用时
- 快速初始化一个空结构体
3. 关键区别总结
特性 | var pre *ListNode | pre := &ListNode{} |
---|---|---|
指针值 | nil | 指向新分配的结构体实例 |
内存分配 | 不分配内存 | 在堆上分配ListNode 内存 |
字段默认值 | 不可访问(nil 指针解引用会panic) | 零值(Val: 0 , Next: nil ) |
安全性 | ❌ 直接访问字段会panic | ✅ 可安全访问字段 |
典型使用场景 | - 延迟初始化 - 接收 nil 参数 | - 立即使用的非空指针 - 哨兵节点 |
4. 进一步对比
内存分配示意图
var pre *ListNode
pre → nil
pre := &ListNode{}
pre → [Val:0, Next:nil]
常见用法示例
// 场景1:延迟初始化
var head *ListNode
if condition {head = &ListNode{Val: 1} // 按需分配
}// 场景2:直接使用
dummy := &ListNode{} // 哨兵节点
dummy.Next = head
其他初始化方式
使用 new 函数
pre := new(ListNode) // 等价于 &ListNode{}
与&ListNode{}
效果相同,但更显式地表明分配内存。
带字段初始化
pre := &ListNode{Val: 1,Next: &ListNode{Val: 2}, // 嵌套初始化
}
如何选择?
-
需要
nil
指针 →var pre *ListNode
(如链表遍历时判断if pre != nil)
-
需要非空指针 →
pre := &ListNode{}
(如创建哨兵节点或临时结构体) -
需要自定义初始值 →
&ListNode{Val: 1}