当您将指针作为参数传递时,幕后发生的事情是创建该指针的副本并将其传递给底层函数。不应将其与引用传递相混淆。
让我们看一个例子以更好地理解它:
package main
import (
"fmt"
)
type Point struct {
x int
y int
}
func (p Point) String() string {
return fmt.Sprintf("(%d, %d)", p.x, p.y)
}
func modifyValue(point Point) {
point.x += 10
}
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)
modifyValue(p)
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)
}
里面发生了什么修改值函数的区别在于修改了一个完全不同的 Point 结构实例,因此调用该函数时传递的值不受影响。
在第二个示例中,传递了指向结构的指针,因此可以以从外部可见的方式修改结构的字段。
最有趣的一点是最后一个函数,修改参考。如果您熟悉其他语言中可用的引用传递范例,您将期望能够完全修改引用的对象,但这不会发生。这是因为你正在修改一个copy作为参数传递的指针。
您可能想知道,如果所有内容都按值传递,那么什么时候应该传递指针以及什么时候应该传递值。传递值可以向调用者函数保证传递的结构不会遭受任何更改,因此当您需要这种行为时,请选择该值。这样做的缺点是会创建整个对象的副本,如果它太大,内存就会成为问题。
如果您将一个大结构作为参数传递,那么使用指针更好,因为它节省空间,但您失去了对象不会遭受任何更改的保证。