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

时间:2015-03-03 06:14:09

标签: go

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

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包中看到了类似的内容。实际上在做什么?

谢谢!

2 个答案:

答案 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)
}