0
package main

import "fmt"

type type1 struct { //T
}

func (t1 type1) type1Meth1() {
    fmt.Printf("==> func (t1 type1) type1Meth1():\n Type: %T\n Value: %+v\n\n", t1, t1)
}

func (t1 *type1) type1Meth2() {
    fmt.Printf("==> func (t1 *type1) type1Meth2():\n Type: %T\n Value: %p\n Contains: %+v\n\n", t1, t1, t1)
}

func (t1 type1) type1Meth3() {
    fmt.Printf("==> func (t1 type1) type1Meth3():\n Type: %T\n Value: %+v\n", t1, t1)
}

type type2 struct { //S
    type1
}

func (t2 *type2) type1Meth3() {
    fmt.Printf("==> func (t2 *type2) type1Meth3(): Type: %T\n Value: %+v\n\n", t2, t2)
}
func main() {
    t2 := type2{}
    t2.type1Meth1() // type2 contains method set of type1
    t2.type1Meth2() // not sure, why this works? type2 does not have method set of *type1 (A)
    t2.type1Meth3() // type2 contains method set of type1. intercepted by embedding type type2 and called with *type2 receiver
}

Gives me:

$ go run embed-struct-in-struct.go
==> func (t1 type1) type1Meth1():
 Type: main.type1
 Value: {}

==> func (t1 *type1) type1Meth2():
 Type: *main.type1
 Value: 0x116be80
 Contains: &{}

==> func (t2 *type2) type1Meth3(): Type: *main.type2
 Value: &{type1:{}}

go version
go version go1.17.2 darwin/amd64

Not sure why call in (A) works? Documentation says: promoted methods are included in the method set of the struct as follows:

Given a struct type S and a defined type T, promoted methods are included in the method set of the struct as follows:

If S contains an embedded field T, the method sets of S and *S both include promoted methods with receiver T. The method set of *S also includes promoted methods with receiver *T. If S contains an embedded field *T, the method sets of S and *S both include promoted methods with receiver T or *T.

1 Answer 1

3

(A) works because the method call implicitly takes the address of the receiver.

The method (*type1).type1Meth2() is promoted to *type2 per the promotion rules quoted in the question.

The section of the specification on calls says:

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

The expression t2.type1Meth2() is shorthand for (&t2).type1Meth2() because t2 is addressable and type1Meth2() is in the method set of *type2.

Sign up to request clarification or add additional context in comments.

1 Comment

wow interesting. The rules for method sets inclusion are not straightforward.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.