我学会了处理指针,在这个例子中,我不明白为什么将i3分配给一个新的当前对象,并做动作current = current.next并不影响i3对象。但是,使用了相同的地址
func main() {
i := &Node{data: 1}
i2 := &Node{data: 2, next: i}
i3 := &Node{data: 3, next: i2}
current := i3
for current.next != nil {
current = current.next
}
log.Println(current)
log.Println(i3)
/*
2020/06/03 12:19:23 &{1 <nil>}
2020/06/03 12:19:23 &{3 0xc42000e1f0}
*/
}
type Node struct {
data int
next *Node
}
而如果我不使用i3对象的副本,该对象在循环中会被很好地修改。
func main() {
i := &Node{data: 1}
i2 := &Node{data: 2, next: i}
i3 := &Node{data: 3, next: i2}
log.Println(i3)
/*
2020/06/03 12:22:05 &{3 0xc42000e1f0}
*/
for i3.next != nil {
i3 = i3.next
}
log.Println(i3)
/*
2020/06/03 12:22:05 &{1 <nil>}
*/
}
current
和 i3
都是指针。
current:= i3
复制一个指针意味着现在 current
将指向同一个地址 i3
点。
指针的复制与被复制的指针没有任何关系,只是两个指针的值相同。所以修改 current
没有任何影响 i3
.
你可以使用这种方式
current := &i3
for (*current).next != nil {
*current = (*current).next
}
现在 current
是一个指针 i3
现在,如果你改变当前的指向值,将影响到 i3
.
在你的第一个例子中,短变量声明。
current := i3
创建一个新变量,名为 current
的指针类型。它是一个不同的变量,比 i3
,但它有相同的指针值。
循环只修改(赋值给)这个 current
变量,所以存储在 i3
永不改变。所以在循环之后 i3
仍然指向具有 data = 3
和 current
将是最后一个,那就是与 data = 1
.
在你的第二个例子中,你没有创建一个 current
变量,但你修改了(分配给 i3
变量。所以在循环之后,它将指向最后一个带有 data = 1
. 在这两种情况下,节点对象都不会被修改,只需修改 current
或 i3
变量。
在第一个例子中,你创建了一个指针式的 current
它将具有相同的值 i3
有(结构体的地址 Node{data: 3, next: i2}
).
当你执行 current = current.next
语句,你只改变指针的值,而不是地址后面的值。你只替换了指针中存储的地址。
如果你按照迭代。
0., current -> Node{data: 3, next: i2}
1., current -> Node{data: 2, next: i}
2., current -> Node{data: 1}
其他指针将保持不变。
i -> Node{data: 1}
i2 -> Node{data: 2, next: i}
i3 -> Node{data: 3, next: i2}
在第二种情况下,你做了非常相同的事情,但是代替了之前的 current
指针,现在你改变了存储在 i3
指针.如果你跟着迭代。
0., i3 -> Node{data: 3, next: i2}
1., i3 -> Node{data: 2, next: i}
2., i3 -> Node{data: 1}
其他指针将保持不变.
i -> Node{data: 1}
i2 -> Node{data: 2, next: i}
当然,你会在内存的某个地方有一个对象,但却无法访问它(Node{data: 3, next: i2})。