Golang method with pointer receiver [duplicate]

I have this example code

package main

import (
    "fmt"
)

type IFace interface {
    SetSomeField(newValue string)
    GetSomeField() string
}

type Implementation struct {
    someField string
}

func (i Implementation) GetSomeField() string {
    return i.someField
}

func (i Implementation) SetSomeField(newValue string) {
    i.someField = newValue
}

func Create() IFace {
    obj := Implementation{someField: "Hello"}
    return obj // <= Offending line
}

func main() {
    a := Create()
    a.SetSomeField("World")
    fmt.Println(a.GetSomeField())
}

SetSomeField does not work as expected because its receiver is not of pointer type.

If I change the method to a pointer receiver, what I would expect to work, it looks like this:

func (i *Implementation) SetSomeField(newValue string) { ...

Compiling this leads to the following error:

prog.go:26: cannot use obj (type Implementation) as type IFace in return argument:
Implementation does not implement IFace (GetSomeField method has pointer receiver)

How can I have the struct implement the interface and the method SetSomeField change the value of the actual instance without creating a copy?

Here's a hackable snippet: https://play.golang.org/p/ghW0mk0IuU

I've already seen this question In go (golang), how can you cast an interface pointer into a struct pointer?, but I cannot see how it is related to this example.


Your pointer to the struct should implement the Interface. In that way you can modify its fields.

Look at how I modified your code, to make it working as you expect:

package main

import (
    "fmt"
)

type IFace interface {
    SetSomeField(newValue string)
    GetSomeField() string
}

type Implementation struct {
    someField string
}    

func (i *Implementation) GetSomeField() string {
    return i.someField
}

func (i *Implementation) SetSomeField(newValue string) {
    i.someField = newValue
}

func Create() *Implementation {
    return &Implementation{someField: "Hello"}
}

func main() {
    var a IFace
    a = Create()
    a.SetSomeField("World")
    fmt.Println(a.GetSomeField())
}

The simple answer is that you won't be able to have the struct implement your interface while having SetSomeField work the way you want.

However, a pointer to the struct will implement the interface, so changing your Create method to do return &obj should get things working.

The underlying problem is that your modified SetSomeField method is no longer in the method set of Implementation. While the type *Implementation will inherit the non-pointer receiver methods, the reverse is not true.

The reason for this is related to the way interface variables are specified: the only way to access the dynamic value stored in an interface variable is to copy it. As an example, imagine the following:

var impl Implementation
var iface IFace = &impl

In this case, a call to iface.SetSomeField works because it can copy the pointer to use as the receiver in the method call. If we directly stored a struct in the interface variable, we'd need to create a pointer to that struct to complete the method call. Once such a pointer is made, it is possible to access (and potentially modify) the interface variable's dynamic value without copying it.