我是Golang的新手,对于指针的工作方式我有点困惑,我正在使用反向链接列表问题作为示例。
func reverseList(head *ListNode) *ListNode {
var prev *ListNode = nil
for {
if head == nil {
break
}
temp := head
head = head.Next
temp.Next = prev
prev = temp
}
return prev
}
在这种情况下,temp
和head
指向相同的内存位置。但是,如果我将temp.Next = prev
行放在head = head.Next
之前,head.Next
将指向零。
当我们说temp.Next = prev
时,幕后发生了什么。我们是说结构temp
指向的是现在已更改,因此如果我将该行放在head = head.Next
之上,那么head
现在也指向此更改的结构?
我认为为了改变head.Next
的实际价值,我们必须取消引用它?
我有点困惑,为什么这不起作用
func reverseList(head *ListNode) *ListNode {
var prev *ListNode = nil
for {
if head == nil {
break
}
temp := head
temp.Next = prev
prev = temp
head = head.Next <--- CHANGED ORDERING HERE
}
return prev
}
答案 0 :(得分:1)
它不起作用,因为你在第一次迭代时使head
无效。这是流程:
temp := head
// Since temp is a pointer, any modifications made to it will also
// impact head. So when you set temp.Next here, you're also setting
// head.Next. Since prev is always nil on the first iteration, you've
// set head.Next = nil.
temp.Next = prev
prev = temp
// This will set head to nil, always.
head = head.Next
在正确的版本中,在发生任何写入之前更新head = head.Next
意味着您已经转移到下一个元素,因此可以安全地覆盖该值。
实际上,第二个版本所做的就是剪掉除第一个版本之外的所有列表元素。如果在调用此函数之前没有引用第二个元素,那么它们现在处于不稳定状态并且将被垃圾收集。
根据评论更新:
当您执行temp := head
之类的操作时,您会说“创建一个名为temp
的指针,并将其指向head
指向的同一事物。”如果您随后修改temp
指向的内容(例如,执行temp.Next = prev
),您还会在读取head
指向的数据时看到更改,因为它仍然指向在同一个地方。
当您执行head = head.Next
时,您说“更新head
指向head.Next
指向的任何地方”。这会更新head
本身而不是其指向的数据,因此您不会看到与temp
相关的任何更改。
这是了解有关指针的更多资源:https://dave.cheney.net/2017/04/26/understand-go-pointers-in-less-than-800-words-or-your-money-back