Kavu
Kavu

Reputation: 8394

Go methods sets — Calling method for pointer type *T with receiver T

Go spec says:

The method set of any other type T consists of all methods with receiver type T. The method set of the corresponding pointer type *T is the set of all methods with receiver *T or T (that is, it also contains the method set of T).

I understand this as: T has its own method set, while *T has it own method set plus the method set of T, because it can dereference receiver *T to T and call the method. Therefore, we can call some method with receiver *T of variable type T.

So I decided to verify my logic:

package main

import (
  "fmt"
  "reflect"
)

type User struct{}

func (self *User) SayWat() {
  fmt.Println(self)
  fmt.Println(reflect.TypeOf(self))
  fmt.Println("WAT\n")
}

func main() {
  var user User = User{}

  fmt.Println(reflect.TypeOf(user), "\n")

  user.SayWat()
}

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

I am a bit confused. It looks like I can call methods "of *T" on T? I have a bit wider example http://play.golang.org/p/RROPMj534A, which confuses me too. Is there some vice versa type inference?

Am I missing something, or my logic is incorrect?

Thanks!

Upvotes: 3

Views: 723

Answers (1)

val
val

Reputation: 8689

You cannot call a method of *T on T, but the compiler is smart enough to take the reference of the variable for you, effectively calling

(&user).SayWat()

This is explained here:

Calls: A method call x.m() is valid if the method set of (the type of) x contains m and the argument list can be assigned to the parameter list of m. If x is addressable and &x's method set contains m, x.m() is shorthand for (&x).m().

To understand the difference, you can for instance take a return value (non-addressable):

func aUser() User {
    return User{}
}

...

aUser().SayWat()

Fails with error:

prog.go:40: cannot call pointer method on aUser()
prog.go:40: cannot take the address of aUser()

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

Upvotes: 10

Related Questions