It's obvious that the following code will work fine:
package main
import "fmt"
type T struct {
a int
}
func (t T) M() {
fmt.Println("M method")
}
func main() {
var t = &T{1}
t.M() // it's interesting
}
But as I can see from specification:
For a value x of type T or *T where T is not a pointer or interface type, x.f denotes the field or method at the shallowest depth in T where there is such an f. If there is not exactly one f with shallowest depth, the selector expression is illegal.
But in example M
is not from *T
, it's from T
. I know that *T
includes method set of T
but as I can see specification doesn't tell us about method set of *T
. Do I understand the specification wrong or correctness of the line with comment is based on some other specification rule?
From Method Sets:
The method set of the corresponding pointer type *T is the set of all methods declared with receiver *T or T (that is, it also contains the method set of T).
You quoted:
x.f
denotes the field or method at the shallowest depth inT
The quote refers to depth. "Definition" of depth is:
A selector
f
may denote a field or methodf
of a typeT
, or it may refer to a field or methodf
of a nested embedded field ofT
. The number of embedded fields traversed to reachf
is called its depth inT
. The depth of a field or methodf
declared inT
is zero. The depth of a field or methodf
declared in an embedded fieldA
inT
is the depth off
inA
plus one.
The key is embedding. Your struct does not embed a single type. So by definition, the depth of your T.M
is zero.
Your t
variable is of type *T
(that is the type of the &T{}
expression, which is taking the address of a struct composite literal: it generates a pointer to a unique variable initialized with the literal's value).
And quoting from Spec: Method values:
As with selectors, a reference to a non-interface method with a value receiver using a pointer will automatically dereference that pointer:
pt.Mv
is equivalent to(*pt).Mv
.
t.M
is a reference to the non-interface method T.M
, and since t
is a pointer, it will be automatically dereferenced: (*t).M()
.
Now let's see an example where the "at the shallowest depth" does matter.
type T struct{}
func (t T) M() { fmt.Println("T.M()") }
type T2 struct {
T // Embed T
}
func (t T2) M() { fmt.Println("T2.M()") }
func main() {
var t T = T{}
var t2 T2 = T2{T: t}
t2.M()
}
In main()
we call t2.M()
. Since T2
embeds T
, this could refer to T2.T.M
and T2.M
. But since depth of T2.T.M
is one and depth of T2.M
is zero, T2.M
being at the shallowest depth in T2
, therefore t2.M
will denote T2.M
and not T2.T.M
, so the above example prints (try it on the Go Playground):
T2.M()