英文:
In golang, how do I re-assign an external reference from within a function?
问题
我可能没有在问题中正确表达,但也许这段代码会更清楚一些:
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
包中见过类似的东西。那实际上是在做什么?
谢谢!
英文:
I'm probably not expressing this correctly in the question, but perhaps this code will make it clearer:
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)
}
Produces, as desired:
x1 = {Message:Internally created by assign1}
x2 = {Message:Internally created by assign2}
I want to pass a reference (pointer to a pointer) into a function and have the function assign a new value to the pointer such that the calling scope will see that new value.
I've figured out the above two ways of doing this, but I'd like to know if they are actually correct or if there is some hidden flaw. Also, are either of them more idiomatic than the other?
Coming from Java, assign2
just seems wrong but I'm sure I've seen something similar in the encoding/json
package. What is that actually doing?
Thanks!
答案1
得分: 2
两种形式都是有效的Go语言,正如你所发现的。
对于assign2
的情况,编译器发现assign2
不在Blob
的方法集中,但它是*Blob
的方法集的一部分。然后,它将方法调用转换为:
(&x2).assign2()
尽管在你的示例中,如果一个方法然后去改变x2
可能会令人困惑,但在标准库中有许多地方使用了这种模式。可能最常见的情况是使用encoding/json
模块为类型实现自定义解码:你使用指针接收器实现DecodeJSON
方法,并更新被指向的值。
英文:
Both forms are valid Go, as you've discovered.
For the assign2
case, the compiler finds that assign2
does not appear in Blob
's method set, but it is part of *Blob
's method set. It then converts the method call to:
(&x2).assign2()
While it can be confusing if a method then goes and changes x2
like in your example, there are a number of places in the standard library where this pattern is used. Probably the most common one is implementing custom decoding for a type with the encoding/json
module: you implement the DecodeJSON
method with a pointer receiver, and update the value being pointed to.
答案2
得分: 2
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 = %+v\n", *x1)
}
英文:
James answers the mechanics of assign2
. I'll touch a bit on when to use it.
Let's take a simpler example, first.
type Counter uint
func (c *Counter) Increment() {
*c += 1
}
In the counter example the entire state of the receiver is changing. Similarly for the encoding/json
package the entire state of the receiver is changing. That's really the only time I would use that style.
One major advantage of the style: you can define an interface for the change, just like the GobDecoder does.
When I first saw the assign2
style it was a little grating. But then I remembered that (c *Counter) Increment
gets translated to Increment(c *Counter)
in the machine code and it didn't bother me anymore. I personally prefer assign1
-style. (Though, there is no need for the double pointers as orignally posted.)
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)
}
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论