英文:
Why does my Go pointer receiver not cause an update?
问题
我很乐意帮助你解释Go语言中指针接收器的工作原理。
你提供了一个二叉搜索树的示例代码,我会用中文翻译一下:
package main
import "fmt"
type Node struct {
key int
left, right *Node
}
func NewNode(key int) *Node {
return &Node{key, nil, nil}
}
type BST struct {
root *Node
}
func NewBinarySearchTree() *BST {
return &BST{nil}
}
func (t *BST) Insert(key int) {
if t.root == nil {
t.root = NewNode(key)
return
}
var node = t.root
for {
if key < node.key {
if node.left == nil {
node.left = NewNode(key)
return
} else {
node = node.left
}
} else {
if node.right == nil {
node.right = NewNode(key)
return
} else {
node = node.right
}
}
}
}
func inorder(node *Node) {
if node == nil {
return
}
inorder(node.left)
fmt.Print(node.key, " ")
inorder(node.right)
}
func main() {
tree := NewBinarySearchTree()
tree.Insert(3)
tree.Insert(1)
tree.Insert(2)
tree.Insert(4)
inorder(tree.root) // 1 2 3 4
}
然后,你尝试简化Insert
函数,代码如下:
func (t *BST) Insert2(key int) {
var node *Node
node = t.root
for node != nil {
if key < node.key {
node = node.left
} else {
node = node.right
}
}
node = NewNode(key)
}
然而,用这种方式实现的话,树将不会被更新。你的思路是这样的:
- 在第一次插入时,根节点将为
nil
。 - 所以,引用
t.root
的局部变量node
也将为nil
。 - 因此,
for
循环将被跳过。 node = NewNode(key)
将具有与t.root = NewNode(key)
相同的效果。
你的Insert2
方法出了什么问题?有没有办法对它进行调整?
英文:
I'd like some help please on how Go pointer receivers work.
I have a contained example below of a binary search tree which hopefully helps me explain.
package main
import "fmt"
type Node struct {
key int
left, right *Node
}
func NewNode(key int) *Node {
return &Node{key, nil, nil}
}
type BST struct {
root *Node
}
func NewBinarySearchTree() *BST {
return &BST{nil}
}
func (t *BST) Insert(key int) {
if t.root == nil {
t.root = NewNode(key)
return
}
var node = t.root
for {
if key < node.key {
if node.left == nil {
node.left = NewNode(key)
return
} else {
node = node.left
}
} else {
if node.right == nil {
node.right = NewNode(key)
return
} else {
node = node.right
}
}
}
}
func inorder(node *Node) {
if node == nil {
return
}
inorder(node.left)
fmt.Print(node.key, " ")
inorder(node.right)
}
func main() {
tree := NewBinarySearchTree()
tree.Insert(3)
tree.Insert(1)
tree.Insert(2)
tree.Insert(4)
inorder(tree.root) // 1 2 3 4
}
After I wrote this, however, I thought I could simplify my insert function as follows:
func (t *BST) Insert2(key int) {
var node *Node
node = t.root
for node != nil {
if key < node.key {
node = node.left
} else {
node = node.right
}
}
node = NewNode(key)
}
However, doing it this way the tree is never updated.
My thinking was...
- on the first insert the root node will be nil.
- so the local variable node which references t.root will also be nil
- the for loop will therefore be skipped.
node = NewNode(key)
will have the same effect ast.root =
NewNode(key)
Where does my Insert2 method go wrong? Is there a way it can be tweaked?
答案1
得分: 3
node = NewNode(key)
这行代码不会改变树的结构。这行代码只是改变了局部变量 node
的指向;在这行代码之后,node
指向一个不同的节点,但它之前指向的节点对象并没有受到影响。要将节点插入到树中,你需要将其赋值给 t.root
、node.left
或者 node.right
。
英文:
node = NewNode(key)
That line doesn't change the tree. That line changes the local variable node
; after this line, node
points to a different Node, but the object it used to point to is unaffected. To insert into the tree, you have to assign to t.root
, node.left
, or node.right
.
答案2
得分: 3
你似乎对指针的使用有些混淆。
当你执行node = t.root
时,你只是让node
指向root
指向的内容。
之后,当你执行node = NewNode(key)
时,你让node
指向一个新创建的项,这不是你想要的;你想要的是让t.root
指向这个新项。
由于你打算修改类型为*Node
(root
、left
和right
)的变量,我们需要一个指向它们的指针,即类型为**Node
的变量,多了一层间接引用。
你可以先让node
指向t.root
的地址,node := &t.root
,然后继续你的循环。
你可以尝试以下代码:
func (t *BST) Insert3(key int) {
node := &t.root
for *node != nil {
if key < (*node).key {
node = &(*node).left
} else {
node = &(*node).right
}
}
*node = NewNode(key)
}
请注意,在循环中,我们使用间接操作符*
来访问引用的数据,包括检查循环中的地址和键。
在函数的最后,*node = NewNode(key)
实现了你最初的意图;你将新创建的项分配给了根、左子树或右子树指针。
英文:
You seem to be confusing the usage of pointers.
When you do node = t.root
, you merely makes node
point to whatever t.root
points to.
Later on, when you do node = NewNode(key)
, you make node
points to a newly created item, which is not what you wanted; you want to make t.root
point to that new item instead.
Since you intend to modify variables which are of type *Node
(root
, left
and right
), we need a pointer to them, so a variable of type **Node
, with one more level of indirection.
You can start by making node
point to the address of t.root
, node := &t.root
, then you proceed to your loop.
You can try something like the following:
func (t *BST) Insert3(key int) {
node := &t.root
for *node != nil {
if key < (*node).key {
node = &(*node).left
} else {
node = &(*node).right
}
}
*node = NewNode(key)
}
Pay attention that we use the indirection operator *
to access the <i>referenced data</i>, when checking the address on the loop, and also the key.
In the end of the function, *node = NewNode(key)
does what you intended to do originally; you are assigning the newly created item to the root, left or right pointers.
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论