我可能没有在问题中正确表达这一点,但也许这段代码会让它更清楚:
package main
import "fmt"
type Blob struct {
Message string
}
func assign1(bb **Blob) {
*bb = &Blob{"Internally created by assign1"}
}
func (b *Blob) assign2() {
*b = Blob{"Internally created by assign2"}
}
func main() {
x1 := &Blob{"Hello World"}
assign1(&x1)
fmt.Printf("x1 = %+vn", *x1)
x2 := Blob{"Hello World"}
x2.assign2()
fmt.Printf("x2 = %+vn", x2)
}
根据需要生产:
x1 = {Message:Internally created by assign1}
x2 = {Message:Internally created by assign2}
我想将一个引用(指向指针的指针)传递到函数中,并让函数为指针分配一个新值,这样调用范围就会看到这个新值。
我已经找到了以上两种方法,但我想知道它们是否真的正确,或者是否存在一些隐藏的缺陷。另外,它们中的一个比另一个更地道吗?
来自Java的assign2
似乎是错误的,但我确信我在encoding/json
包中看到过类似的东西。那到底在干什么?
谢谢!
assign2
的力学问题。我会谈谈什么时候使用它。
让我们先举一个简单的例子。
type Counter uint
func (c *Counter) Increment() {
*c += 1
}
在反例中,接收器的整个状态正在改变。类似地,对于encoding/json
包,接收器的整个状态正在改变。那真的是我唯一一次使用那种风格。
这种风格的一个主要优点是:您可以像GobDecoder一样为更改定义一个接口。
当我第一次看到assign2
风格时,它有点刺耳。但后来我想起了(c *Counter) Increment
在机器代码中被翻译成Increment(c *Counter)
,这不再困扰我了。我个人更喜欢assign1
风格。(不过,没有必要像最初发布的那样使用双指针。)
package main
import "fmt"
type Blob struct {
Message string
}
func assign1(b *Blob) {
*b = Blob{"Internally created by assign1"}
}
func main() {
x1 := Blob{"Hello World"}
assign1(&x1)
fmt.Printf("x1 = %+vn", *x1)
}
正如您所发现的,这两种形式都是有效的Go。
对于assign2
的情况,编译器发现assign2
没有出现在Blob
的方法集中,但它是*Blob
的方法集的一部分。然后它将方法调用转换为:
(&x2).assign2()
虽然如果一个方法像您的示例中那样继续并更改x2
可能会令人困惑,但在标准库中有许多地方使用了这种模式。最常见的可能是使用encoding/json
模块实现类型的自定义解码:使用指针接收器实现DecodeJSON
方法,并更新所指向的值。