繁体   English   中英

GoLang 指针表现得很奇怪

[英]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")
    }
}

基本上为什么不打印“Equalsss2”? 我感觉既然改了node2.Next但没改node2,node2应该等于temp 为什么不是呢?

您的代码中没有行为不当的指针。 我怀疑你认为的指针实际上并不是指针,因此你很困惑。

在您的代码中, node1node2ListNode结构,即 _ value types 当您将node2分配给temp时, temp会保存node2副本而不是指向它的指针或引用。

在 Go 中,(简单来说)如果两个结构值具有相同的类型并且由可比较的字段组成且都被评估为相等,则它们是相等的。

当您最初比较node2temp时,这两个值中每个值的所有字段的值都相同,因此temp == node2的计算结果为真。

然后更改node2Next字段,因此当您再次比较temp == node2时,它们不再相等,因为它们在该字段的值上不同。

要获得您期望的行为, node1node2需要是指向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 即指针tempnode2相等; 他们都指向同一个ListNode

现在,当您更改node2.Next时,这不会影响temp仍然只是node2指针的副本这一事实,并且由于node2本身(指针)和temp的值都没有改变,它们仍然相等。

即,如果您使用指针,您的代码将按预期运行。 如果您认为指针表现得“怪异”,那是因为在这种情况下,您实际上并没有使用指针。 :)

正如您问题的评论者试图指出的那样,这里没有发生任何奇怪的事情。 在您的第一个条件之后添加:

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)

这将是 output:

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)

这将是 output:

temp.Next has Val: 10
node2.Next has Val: 1

你可以在这里看到结果。

node2temp指向不同的对象,在您修改node.Next之前,这两个对象具有相同的字段值。 您的分配temp:= node2 make 创建了结构类型的新实例,并复制了源 object 中的值。它不会创建指向node object 的指针 - 如果有,则更改node2.<field>也会更改temp.<field> 这有点令人困惑,因为在 go 中(与 C 不同)您不需要取消引用指针/使用不同的访问器语法来访问结构字段,因此以下内容完全没问题:

temp := &node2
node2.Val = 500
fmt.Printf("%d == %d\n, temp.Val, node2.Val)

最终,这里的一切都如人们所想的那样发生着。 换句话说,您的第一个条件是检查相等性而不是身份。 具有相同值(平等)的不同对象(身份)。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM