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?
CodePudding user response:
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. :)
CodePudding user response:
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).