Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Golang method with pointer receiver [duplicate]

Tags:

go

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.

like image 436
Atmocreations Avatar asked Nov 26 '15 10:11

Atmocreations


People also ask

Is it possible to call methods that are declared with a value receiver using a pointer?

you can mix and match methods with value receivers and methods with pointer receivers, and use them with variables containing values and pointers, without worrying about which is which. Both will work, and the syntax is the same.

What is pointer receiver in Golang?

You can declare methods with pointer receivers. This means the receiver type has the literal syntax *T for some type T . (Also, T cannot itself be a pointer such as *int .) For example, the Scale method here is defined on *Vertex .

What type of receiver is used to avoid copying the value on each method call?

There are two reasons to use a pointer receiver. The first is so that the method can modify the value that its receiver points to. The second is to avoid copying the value on each method call.

What's the difference between a method and a function in Golang?

Go methods are similar to Go function with one difference, i.e, the method contains a receiver argument in it. With the help of the receiver argument, the method can access the properties of the receiver. Here, the receiver can be of struct type or non-struct type.


2 Answers

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()) } 
like image 60
nessuno Avatar answered Sep 18 '22 14:09

nessuno


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.

like image 38
James Henstridge Avatar answered Sep 18 '22 14:09

James Henstridge