例如

var myStructRef *Vertex
var myStruct Vertex
myStructRef = &Vertex{2, 3}
myStruct = Vertex{2, 3}

fmt.Println(myStructRef)
fmt.Println(myStruct)
changeByReferenceStruct(myStructRef)
changeByValueStruct(myStruct)
fmt.Println(myStructRef)
fmt.Println(myStruct)

func changeByValueStruct(myStruct Vertex) {
    myStruct.X = 5
    fmt.Println(myStruct)
}


func changeByReferenceStruct(myStruct *Vertex) {
    myStruct.X = 7
    fmt.Println(myStruct)
}

myStructRef *VertexmyStruct Vertex不都是指向 struct 本身的指针吗?为什么当我修改函数中的 struct 时,行为会有差异?

Golang在解析参数时是否在changeByValueStruct中创建新 struct ?

推荐答案

当您将指针作为参数传递时,幕后发生的事情是创建该指针的副本并将其传递给底层函数.不应将其与按引用传递混淆.

为了更好地掌握它,我们来看一个例子:

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)
}

modifyValue函数内部发生的事情是修改了点 struct 的一个完全不同的实例,因此调用该函数时传递的值不受影响.

在第二个示例中,传递了指向该 struct 的指针,因此可以通过从外部可见的方式修改该 struct 的字段.

最有趣的一点是最后一个函数modifyReference.如果您熟悉其他语言中提供的Pass by Reference范例,您会希望能够完全修改被引用的对象,但这并不会发生.这是因为您正在修改作为参数传递的指针的copy.

您可能会想,如果所有东西都是通过值传递的,那么应该在什么时候传递指针,什么时候传递值.传递值可确保调用程序函数传递的 struct 不会发生任何更改,因此当您需要此行为时,请使用该值.这样做的缺点是制作了整个对象的副本,如果它太大,内存就会成为一个问题.

如果要将大 struct 作为参数传递,则使用指针更好,因为它节省了空间,但失go 了对象不会遭受任何更改的保证.

Go相关问答推荐

try 用GitHub操作中的release标签更新version. go文件,但失败了

调用API时使用nginx作为反向代理时从nginx获取502坏网关

理解Golang并发:缓冲通道的意外行为

为什么我不能使用Docker从本地访问我的Gin应用程序?

困扰围棋官方巡回赛的S建议所有方法都使用同一类型的接收器

错误.如果它包含切片,则返回FALSE

我找不到pcap.Openlive的设备名称

Python样式生成器实现为通道:过早读取

使用 goroutine 比较 Golang 中的两棵树是等价的

htmx 表单 + gin 无法正确读取请求正文

在 Cloud Run 中找不到默认凭据

上传图片失败,出现错误dial tcp: lookup api.cloudinary.com: no such host

无法使用 gocsv 读取引用字段

通过环境变量配置 OTLP 导出器

如何在gin中获取参数值数组

使用 image/jpeg 编码导致图像饱和/错误像素

具有相同提前返回语句的函数的不同基准测试结果

如何解决在mac m1中运行gcc失败退出状态1?

如何允许可转换为指针的泛型类型参数化另一种可转换为指针的泛型类型?

Gorilla/Mux 和 Websocket 竞赛条件,这安全吗?