Method defined on a pointer still being called with a value

The Efficient Transition documentation reads as follows.

The rule of thumb for pointers and values ​​for sinks is that value methods can be called by pointers and values, but pointer methods can only be called by pointers.

http://tip.golang.org/doc/effective_go.html#pointers_vs_values

As such, if I define a method like the following, can't it be called with a value?

func (self *someStruct) Change(newNum int) {
    self.propertyOne = newNum
}

      

However, it looks like it still works.

structInstance := &someStruct{
    propertyOne: 41,
}
(*structInstance).Change(456)

      

Why?

Does the value convert (*structInstance)

back to an address / pointer for the call Change

?

How can I ensure that some instance of a type cannot call a method defined on a pointer (for example Change

)?

Go to the playground demo

http://play.golang.org/p/azbpp_djlG

+3


source to share


2 answers


From the language specification :

A method call is x.m()

valid if the method set (type) x

contains m

, and the argument list can be assigned to the parameter list m

. If x

addressed and method &x

contains m

, x.m()

is shorthand for(&x).m()



In your example, there is no method Change

in the method (*structInstance)

, but it is addressed and the method exists in the method &(*structInstance)

, so the call is interpreted as (&(*structInstance)).Change(456)

or more simply structInstance.Change(456)

.

The only way to prevent this behavior is to define the Change

on method as well someStruct

, possibly making it panic. It's not ideal though, as it will only tell you about the runtime problem. It would be less confusing to structure your program so that using this shorthand copy doesn't really matter.

+1


source


When a function is defined in a pointer receiver, Go will automatically convert the value to a pointer for that function.

type Cookies struct {
    Num int
}

func (c *Cookies) Buy(n int) {
    c.Num += n
}

func main() {
    c := Cookies{}
    c.Buy(10) //is equal to (&c).Buy(10)
    fmt.Println(c)
}

      

I can't seem to find a link to where this is defined right now, but I know it in the official docs somewhere in the specs.

Also note, please don't use self

or this

in Go.



//edit

From http://tip.golang.org/ref/spec#Calls :

The method call xm () is valid if the method set (type) x contains m, and the argument list can be assigned to the parameter list m. If x is addressable and the method set & x contains m, xm () is shorthand for (& x) .m ()

+2


source







All Articles