英文:
GoLang pointers are behaving wierd
问题
为什么在下面的代码中改变node2.Next会影响到node2?
import "fmt"
type ListNode struct {
Val int
Next *ListNode
}
func main() {
node1 := ListNode{Val: 10, Next: nil}
node2 := ListNode{Val: 100, Next: &node1}
temp := node2
if temp == node2 {
fmt.Println("Equalssss1")
}
node2.Next = &(ListNode{1, nil})
if temp == node2 {
fmt.Println("Equalssss2")
}
}
基本上为什么没有打印出"Equalssss2"?我觉得由于改变了node2.Next但没有改变node2,node2应该等于temp,为什么不是这样呢?
英文:
Why does changing node2.Next affects node2 in the below code?
import "fmt"
type ListNode struct {
Val int
Next *ListNode
}
func main() {
node1 := ListNode{Val:10 , Next:nil}
node2 := ListNode{Val:100 , Next:&node1}
temp := node2
if(temp == node2){
fmt.Println("Equalssss1")
}
node2.Next = &(ListNode{1 , nil})
if(temp == node2){
fmt.Println("Equalssss2")
}
}
Basically why doesn't "Equalssss2" doesn't get printed? I feel since node2.Next is changed but not node2, node2 should be equal to temp Why isn't it the case?
答案1
得分: 2
你的代码中没有出现指针错误。我怀疑你认为的指针实际上并不是指针,所以才会感到困惑。
在你的代码中,node1
和node2
是ListNode
结构体,也就是值类型。当你将node2
赋值给temp
时,temp
实际上是node2
的一个副本,而不是指向它的指针或引用。
在Go语言中(简单来说),如果两个结构体的值类型相同,并且它们的所有字段都是可比较的且相等,那么它们就是相等的。
当你最初比较node2
和temp
时,两个值的所有字段的值都是相同的,因此temp == node2
的结果为true。
然后你改变了node2
的Next
字段,因此当你再次比较temp == node2
时,它们不再相等,因为它们在该字段的值上有所不同。
要获得你期望的行为,node1
和node2
需要是指向ListNode
的指针:
type ListNode struct {
Val int
Next *ListNode
}
func main() {
node1 := &ListNode{Val: 10, Next: nil}
node2 := &ListNode{Val: 100, Next: node1}
temp := node2
if temp == node2 {
fmt.Println("Equalssss1")
}
node2.Next = &(ListNode{1, nil})
if temp == node2 {
fmt.Println("Equalssss2")
}
}
现在,temp
也是指向ListNode
的指针,而不是ListNode
值的副本;temp
被初始化为引用与node2
相同的ListNode
。也就是说,指针temp
和node2
是相等的,它们都指向同一个ListNode
。
现在,当你改变node2.Next
时,这不会影响到temp
仍然只是node2
指针的副本,由于node2
本身(指针)的值和temp
都没有改变,它们仍然相等。
也就是说,如果你使用了指针,你的代码将会按照预期的方式运行。如果你认为指针的行为很奇怪,那是因为在这种情况下,你实际上并没有使用指针。
英文:
There are no misbehaving pointers in your code. I suspect that what you think are pointers are not actually pointers, hence your confusion.
In your code node1
and node2
are ListNode
structs, i.e. _value types. When you assign node2
to temp
, temp
then holds a copy of node2
, not a pointer or reference to it.
In Go, (in simple terms) two struct values are equal if they of the same type and consist of comparable fields that all evaluate as equal.
When you initially compare node2
and temp
the values of all of the fields in each of the two values are the same, therefore temp == node2
evaluates true.
You then change the Next
field of node2
, therefore when you again compare temp == node2
they are no longer equal since they differ in the value of that field.
To get the behaviour you are expecting, node1
and node2
would need to be pointers to a ListNode
:
type ListNode struct {
Val int
Next *ListNode
}
func main() {
node1 := &ListNode{Val: 10, Next: nil}
node2 := &ListNode{Val: 100, Next: node1}
temp := node2
if temp == node2 {
fmt.Println("Equalssss1")
}
node2.Next = &(ListNode{1, nil})
if temp == node2 {
fmt.Println("Equalssss2")
}
}
temp
is now also a pointer to a ListNode
, rather than a copy of the ListNode
value; temp
is initialised to reference the same ListNode
that node2
references. That is, the pointers temp
and node2
are equal; they both point to the same ListNode
.
Now, when you change node2.Next
, this doesn't affect the fact that temp
is still just a copy of the node2
pointer and since neither the value of node2
itself (the pointer) nor temp
have changed, they are still equal.
i.e. if you were using pointers, your code would behave as expected. If you think that pointers are behaving "weirdly" it is because, in this instance, you are not actually using pointers.
答案2
得分: 2
正如评论者在你的问题中指出的那样,这里没有发生任何奇怪的事情。在你的第一个条件语句之后添加以下代码:
fmt.Printf("temp is at %p and temp.Next is at %p\nnode2 is at %p and node2.Next is at %p\n", &temp, temp.Next, &node2, node2.Next)
这将输出:
temp is at 0xc00009e240 and temp.Next is at 0xc00009e220
node2 is at 0xc00009e230 and node2.Next is at 0xc00009e220
在你的第二个条件语句之后添加以下代码:
fmt.Printf("temp.Next has Val: %d\nnode2.Next has Val: %d\n", temp.Next.Val, node2.Next.Val)
这将输出:
temp.Next has Val: 10
node2.Next has Val: 1
你可以在这里看到结果。
node2
和 temp
指向不同的对象,它们的字段值相同,直到你修改 node.Next
。你的赋值语句 temp := node2
创建了一个结构体类型的新实例,并将源对象的值复制进去。它并没有创建一个指向 node
对象的指针——如果它这样做了,那么改变 node2.<field>
也会改变 temp.<field>
。这在某种程度上会让人感到困惑,因为在 Go 中(与 C 不同),你不需要解引用指针/使用不同的访问器语法来访问结构体字段,所以下面的代码是完全正确的:
temp := &node2
node2.Val = 500
fmt.Printf("%d == %d\n, temp.Val, node2.Val)
最后,这里的一切都按照人们的预期发生。换句话说,你的第一个条件语句检查的是相等性而不是身份。不同的对象(身份)具有相同的值(相等性)。
英文:
As the commenters on your question are trying to point out, nothing at all weird is happening here. Add this after your first conditional:
fmt.Printf("temp is at %p and temp.Next is at %p\nnode2 is at %p and node2.Next is at %p\n", &temp, temp.Next, &node2, node2.Next)
this will output:
temp is at 0xc00009e240 and temp.Next is at 0xc00009e220
node2 is at 0xc00009e230 and node2.Next is at 0xc00009e220
and try adding this line after your second conditional:
fmt.Printf("temp.Next has Val: %d\nnode2.Next has Val: %d\n", temp.Next.Val, node2.Next.Val)
which will output:
temp.Next has Val: 10
node2.Next has Val: 1
You can see the result here.
node2
and temp
point to different objects, both of which have the same field values until you modify node.Next
. Your assignment temp := node2
makes creates a new instance of the struct type and copies in the values from the source object. It does not create a pointer to the node
object - if it had, then changing node2.<field>
would also change temp.<field>
. This is made slightly confusing by the fact that, in go (unlike in say C) you do not need to dereference the pointer/use different accessor syntax to access struct fields, so the following would be completely fine:
temp := &node2
node2.Val = 500
fmt.Printf("%d == %d\n, temp.Val, node2.Val)
In the end, everything here is happening exactly as one would expect. Put another way, your first conditional is checking equality but not identity. Different objects (identity) with the same values (equality).
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论