Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Replace value of interface

Tags:

pointers

go

I want to replace an interface's value like this:

package main
import "fmt"

type Fooer interface {Foo(string)}

type Foo struct {foo string}

func (f *Foo) Foo(bar string) {f.foo = bar}

var z = &Foo{foo : "new"}

func swap(fooer Fooer) {fooer = z}

func main() {
    f :=  &Foo{foo: "old"}
    fmt.Printf("%s (want &{old})\n", f)
    swap(f)
    fmt.Printf("%s (want &{new})", f)
}

But i get:

&{old}
&{old}

I tried around with various calls (fooer *= z, *fooer = *z, ..) but I cant seem to get it right.

You can try this example at play.golang: http://play.golang.org/p/EZEh3X8yHC


Okay, I think it works like this:

func swap(fooer Fooer) {
    foo, _ := fooer.(*Foo)
    *foo = *z
}
like image 482
machete Avatar asked Jan 15 '16 18:01

machete


1 Answers

Like most things in Go, interfaces are simply values. Assigning a new value within a function isn't going to change the value copied into the function arguments.

Because you want to replace the interface value, you need a pointer to the value just like you would any other. It's a very rare case where you could use a pointer to an interface: http://play.golang.org/p/EZEh3X8yHC

func swap(fooer *Fooer) {
    z := Fooer(&Foo{foo: "new"})
    *fooer = z
}

func main() {
    var f Fooer = &Foo{foo: "old"}
    fmt.Printf("%s (want &{old})\n", f)
    swap(&f)
    fmt.Printf("%s (want &{new})", f)
}

But, since a pointer to an interface is almost always a mistake (you can see we have to be very explicit to make this work), you should really have a good reason for implementing something this way, and document it well.

What you most likely want is to extract the pointer from the interface, and assign a new value in there (which is what you added to end of your question). This is a much better construct, but the type must match, so the interface isn't needed.

like image 199
JimB Avatar answered Oct 29 '22 07:10

JimB