我是 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
指向相同的内存位置。但是如果我把行放在head = head.Next
前面temp.Next = prev
,head.Next
将指向 nil。
当我们说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
}
它不起作用,因为您在第一次迭代时使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