我可能没有在问题中正确表达这一点,但也许这段代码会更清楚:
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 = %+v\n", *x1)
x2 := Blob{"Hello World"}
x2.assign2()
fmt.Printf("x2 = %+v\n", x2)
}
根据需要制作:
x1 = {Message:Internally created by assign1}
x2 = {Message:Internally created by assign2}
我想将一个引用(指针指针)传递给一个函数,并让函数为指针赋一个新值,使调用范围看到新值。
我已经找到了上述两种方法,但我想知道它们是否真的正确或是否存在隐藏的缺陷。另外,他们中的任何一个都比其他更惯用吗?
来自Java,assign2
似乎错了,但我确信我在encoding/json
包中看到了类似的内容。实际上在做什么?
谢谢!
答案 0 :(得分:2)
这两种形式都是有效的Go,正如您所发现的那样。
对于assign2
情况,编译器发现assign2
的方法集中没有出现Blob
,但它是*Blob
&#的一部分39; s方法集。然后它将方法调用转换为:
(&x2).assign2()
虽然如果某个方法随后更改x2
会让您感到困惑,但在标准库中有许多地方使用此模式。可能最常见的是为具有encoding/json
模块的类型实现自定义解码:使用指针接收器实现DecodeJSON
方法,并更新指向的值。
答案 1 :(得分:2)
James answers assign2
的机制。我会稍微谈谈何时使用它。
首先让我们举一个更简单的例子。
type Counter uint
func (c *Counter) Increment() {
*c += 1
}
在计数器示例中,接收器的整个状态正在发生变化。类似地,对于encoding/json
包,接收器的整个状态正在发生变化。这是我唯一一次使用这种风格。
样式的一个主要优点:您可以为更改定义界面,就像GobDecoder一样。
当我第一次看到assign2
样式时,它有点光栅。但后来我记得(c *Counter) Increment
在机器代码中被转换为Increment(c *Counter)
,它不再困扰我了。我个人更喜欢assign1
- 风格。 (尽管如此,双指针有no need作为orignally发布。)
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 = %+v\n", *x1)
}