了解指针接收器和复制实例
在 Go 中,可以使用值接收器或指针接收器来定义方法。当类型 T 的所有方法都有 T 本身的接收者类型时,复制该类型的实例是安全的,因为调用其任何方法都必然会进行复制。
然而,当类型有带有指针接收器的方法。在这种情况下,应避免复制该类型的实例,因为它可能违反内部不变量。
复制指针的问题
让我们考虑一个示例来说明问题。假设我们有一个带有两个字段的类型 Wrapper:值 v 和指针 p。我们打算在 v 和 p 的指向值中存储相同的数字。为了确保这一点,我们提供了一个带有指针接收器的 Set 方法:
type Wrapper struct {
v int
p *int
}
func (w *Wrapper) Set(v int) {
w.v = v
*w.p = v
}
如果我们有一个Wrapper实例并调用Set方法,它将修改p的指向值。但是,如果我们创建实例的副本,则副本将与原始实例共享相同的指针值 p。这意味着对任一实例的任何后续方法调用都会影响两个副本。
示例:
a := Wrapper{v: 0, p: new(int)}
b := a
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
在此示例中,调用 a.Set(1) 后,b 的值无效,因为 b.v 不等于 *b.p。这是因为 a 和 b 中的指针 p 都指向相同的基础值。
为了避免此类问题,建议在使用带有指针接收器的方法时使用指针值。或者,如果该类型只能具有值接收器,则无论方法调用如何,复制该类型的实例都是安全的。
免责声明: 提供的所有资源部分来自互联网,如果有侵犯您的版权或其他权益,请说明详细缘由并提供版权或权益证明然后发到邮箱:[email protected] 我们会第一时间内为您处理。
Copyright© 2022 湘ICP备2022001581号-3