一个令人费解的 go 指针问题
在 go 语言中,值传递是传递值副本的过程。不过,当传递指针时,就会出现一个有点让人困惑的现象。以以下代码为例:
package main type point struct { x int y int } func (p point) string() string { return fmt.sprintf("(%d, %d)", p.x, p.y) } func modifypointer(point *point) { point.x = 5 point.y = 5 } func modifyreference(point *point) { point = &point{5, 5} } func main() { p := point{0, 0} fmt.println(p) // prints (0, 0) modifypointer(&p) fmt.println(p) // prints (5, 5) p = point{0, 0} modifyreference(&p) fmt.println(p) // prints (0, 0) 令人困惑之处,我们希望得到 (5, 5) }
登录后复制
上面的代码中,modifypointer 和 modifyreference 都传递了指针,但只有 modifypointer 成功改变了原始值。造成这种不同行为的原因是什么?
在调用这两个函数时,传递的都是指向 p 的指针。因此,modifypointer 和 modifyreference 内部收到的参数都是 p 的指针副本。
modifypointer 函数中对 point 的修改是通过访问 point 指向的实际 point 值,并直接修改其字段来实现的。由于 point 是一个指针副本,这些更改不会影响原始值。
另一方面,modifyreference 函数尝试将 point 重新分配给一个新的 point 值。然而,point 只是原始指针的一个副本。因此,当在 modifyreference 内部更改 point 时,它不会影响原始指针所指向的值。
为了在 modifyreference 中实现同样的效果,可以如下修改代码:
func modifyReference(point *Point) { *point = Point{5, 5} }
登录后复制
通过使用星号 (*,即解引用运算符),可以在 modifyreference 内部访问原始 point 值并更改其字段。这样就能在外部正确修改 point 值。