This story explains remaining content from language specification touching methods. It’s strongly advised to read 1st part of the introduction.

Method expressions

Having type T whose method set contains method M, T.M yields a function with signature almost as in method M. It’s called method expression. The difference is additional first parameter of type equal to type of M’s receiver:

package main import (

"fmt"

"reflect"

) func PrintFunction(val interface{}) {

t := reflect.TypeOf(val)

fmt.Printf("Is variadic: %v

", t.IsVariadic())

for i := 0; i < t.NumIn(); i++ {

fmt.Printf("Parameter #%v: %v

", i, t.In(i))

}

} type T struct{} func (t T) M(text string, number int) {}

func (t *T) N(map[string]int) {} func main() {

PrintFunction(T.M)

PrintFunction((*T).M)

PrintFunction((*T).N)

}

output:

Is variadic: false

Parameter #0: main.T

Parameter #1: string

Parameter #2: int

Is variadic: false

Parameter #0: *main.T

Parameter #1: string

Parameter #2: int

Is variadic: false

Parameter #0: *main.T

Parameter #1: map[string]int

Expression T.N would causes an error invalid method expression T.N (needs pointer receiver: (*T).N) since method N is not in method set of T.

One interesting case is PrintFunction((*T).M) from the snippet above. It creates function with first parameter of type *main.T even so the method M has value receiver. Go’s runtime under the hood indirects passed pointer, creates copy and passes it to the method. This way method doesn’t have access to the original value:

type T struct {

name string

} func (t T) M() {

t.name = "changed"

} func (t *T) N() {

t.name = "changed"

} func main() {

t := T{name: "Michał"}

(*T).M(&t)

fmt.Println(t.name)

(*T).N(&t)

fmt.Println(t.name)

}

output:

Michał

changed

Method expression can be created out of the interface type:

package main import "fmt" type T struct {

name string

} func (t T) M() {

fmt.Println(t.name)

} type I interface {

M()

} func main() {

t1 := T{name: "Michał"}

t2 := T{name: "Tom"}

m := I.M

m(t1)

m(t2)

}

output:

Michał

Tom

Method values

Similarly as with types and method expressions, having an expression it’s possible to get a function with receiver bound to that expression — method value. Having an expression x, x.M is a callable taking the same arguments as method M. Of course M needs to be in method set of x’s type or x is addressable and M is in the method set of &x’s type:

type T struct {

name string

} func (t *T) M(string) {}

func (t T) N(float64) {} func main() {

t := T{name: "Michał"}

m := t.M

n := t.N

m("foo")

n(1.1)

}

Promoted methods

If struct contains embedded (anonymous) fields then promoted methods are members of type’s method set:

package main import "fmt" type T struct {

name string

} func (t T) M() string {

return t.name

} type U struct {

T

} func main() {

u := U{T{name: "Michał"}}

fmt.Println(u.M())

}

It’s a completely valid Go program which outputs Michał . There are certain rules when methods from embedded fields are part of encompassing type’s method set:

#1

When struct type U contains embedded field T then method sets of S and *S contain promoted methods with receiver T. Additionally method set of *S contains promoted methods with receiver *T.

package main import (

"fmt"

"reflect"

)

func PrintMethodSet(val interface{}) {

t := reflect.TypeOf(val)

fmt.Printf("Method set count: %d

", t.NumMethod())

for i := 0; i < t.NumMethod(); i++ {

m := t.Method(i)

fmt.Printf("Method: %s

", m.Name)

}

} type T struct {

name string

} func (t T) M() {}

func (t *T) N() {} type U struct {

T

} func main() {

u := U{T{name: "Michał"}}

PrintMethodSet(u)

PrintMethodSet(&u)

}

Output is as follows:

Method set count: 1

Method: M

Method set count: 2

Method: M

Method: N

What should be known from the first part of the introduction is an additional calling rule from language’s specification:

If x is addressable and &x’s method set contains m, x.m() is shorthand for (&x).m().

Because of that we can call u.N() even so the method N is not a part of method set of type U.

#2

When struct type U contains embedded field *T then method sets of S and *S contain promoted methods with receiver T or *T:

type T struct {

name string

} func (t T) M() {}

func (t *T) N() {} type U struct {

*T

} func main() {

u := U{&T{name: "Michał"}}

PrintMethodSet(u)

PrintMethodSet(&u)

}

prints: