复制实例时指针接收器的重要性
操作数据时,理解按引用或按值传递值的细微差别至关重要。在 Go 中,方法可以使用值接收器或指针接收器来定义,理解这种选择的含义至关重要,尤其是在复制实例时。
值接收器
具有值接收器的方法对它们接收到的值的副本进行操作。方法内所做的任何修改都不会影响原始值。这确保了在复制的实例上调用方法不会损害原始数据。
指针接收器
相反,具有指针接收器的方法允许直接访问和修改原始值。此类方法有可能改变数据,从而导致微妙且意想不到的副作用。使用指针接收器复制实例存在在原始数据和复制数据之间引入不一致的风险。
示例:Wrapper Struct
为了说明该问题,请考虑一种称为 Wrapper 的类型包含字段 v(值)和 p(指向值的指针):
type Wrapper struct {
v int
p *int
}
带有指针接收器的 Set() 方法同时修改 v 和指向的值:
func (w *Wrapper) Set(v int) {
w.v = v
*w.p = v
}
假设我们有一个 Wrapper 实例 a:
a := Wrapper{v: 0, p: new(int)}
调用 Set() on a 将同时修改 v 和 *p:
a.Set(1)
现在,如果我们复制 a 来创建 b,我们期望两个实例将具有一致的值:
b := a
但是,后续使用Set()对a的修改,由于指针p的复制,不会传播到b,导致数据不一致:
fmt.Printf("a.v=%d, a.p=%d; b.v=%d, b.p=%d\n", a.v, *a.p, b.v, *b.p)
a.Set(1)
fmt.Printf("a.v=%d, a.p=%d; b.v=%d, b.p=%d\n", a.v, *a.p, b.v, *b.p)
输出:
a.v=0, a.p=0; b.v=0, b.p=0 a.v=1, a.p=1; b.v=0, b.p=1
结论
处理具有指针接收器方法的类型时,避免复制实例以防止数据不一致至关重要。相反,对指针值进行操作以确保修改反映在引用相同基础数据的所有实例中。
免责声明: 提供的所有资源部分来自互联网,如果有侵犯您的版权或其他权益,请说明详细缘由并提供版权或权益证明然后发到邮箱:[email protected] 我们会第一时间内为您处理。
Copyright© 2022 湘ICP备2022001581号-3