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

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
", *x1)

    x2 := Blob{"Hello World"}
    x2.assign2()
    fmt.Printf("x2 = %+v
", 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!

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
", *x1)
}

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.