Golang method with pointer receiver

Go

Go Problem Overview


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 https://stackoverflow.com/questions/29221854/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.

Go Solutions


Solution 1 - Go

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())
}

Solution 2 - Go

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.

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
QuestionAtmocreationsView Question on Stackoverflow
Solution 1 - GonessunoView Answer on Stackoverflow
Solution 2 - GoJames HenstridgeView Answer on Stackoverflow