树节点必须用指针而非值类型,因值类型会导致无限递归复制和编译错误;*TreeNode合法且只存地址,但需注意nil指针panic、显式初始化、遍历时判空及内存性能影响。
为什么树节点必须用指针而不能用值类型
Go 中结构体默认按值传递,如果 TreeNode 定义为值类型,每次赋值或传参都会复制整个结构体;更关键的是,子节点字段(如 Left、Right)若也存值类型,就会触发无限嵌套复制——编译器直接报错 invalid recursive type TreeNode。所以必须用指针:*TreeNode 是合法的,它只存地址,不引发递归定义。
常见错误写法:
type TreeNode struct {
Val int
Left TreeNode // ❌ 编译失败:recursive type
Right TreeNode
}
正确写法:
type TreeNode struct {
Val int
Left *TreeNode // ✅ 指针可指向自身类型
Right *TreeNode
}
如何安全地初始化和连接树节点
直接对 nil 指针解引用会 panic,所以新建节点后必须显式分配内存。常见误区是以为 var n *TreeNode 就能直接用 n.Left = &TreeNode{...}——其实 n 还是 nil,n.Left 会触发 panic。
- 用
&TreeNode{Val: 1}或new(TreeNode)创建非 nil 指针 - 连接子节点前,确保父节点指针已初始化(不是 nil)
- 批量建树时推荐用辅助函数封装,避免重复判空
示例: