在golang中,如何从函数中重新分配外部引用



我可能没有在问题中正确表达这一点,但也许这段代码会让它更清楚:

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包中看到过类似的东西。那到底在干什么?

谢谢!

James回答了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方法,并更新所指向的值。

最新更新