The title of the question is almost quoted from the golang specification:
Given a struct type S and a type named T, promoted methods are included in the method set of the struct as follows:
- If S contains an anonymous 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.
This is a go playground shows that The method inc()
is promoted.
package main
import (
"fmt"
)
// just an int wrapper
type integer struct {
i int
}
func (self *integer) inc() {
self.i++
}
type counter struct {
integer
}
func main() {
c := counter{}
c.inc()
fmt.Println(c)
}
This distinction arises because if an interface value contains a pointer *T, a method call can obtain a value by dereferencing the pointer, but if an interface value contains a value T, there is no safe way for a method call to obtain a pointer.
In a method set, each method must have a unique non-blank method name. The method set of a type determines the interfaces that the type implements and the methods that can be called using a receiver of that type.
New() Function in Golang is used to get the Value representing a pointer to a new zero value for the specified type. To access this function, one needs to imports the reflect package in the program.
No the methods of *T would not be promoted. The specification doesn't explicitly allow it so it isn't allowed. However, there is a reason behind this.
At times you may call a *T method on T. However, there is an implicit reference taken. Methods of *T are not considered part of T's method set.
From the calls section of the Go specification:
If x is addressable and &x's method set contains m, x.m() is shorthand for (&x).m()
From the address operator section of the Go specification:
For an operand x of type T, the address operation &x generates a pointer of type *T to x. The operand must be addressable, that is, either a variable, pointer indirection, or slice indexing operation; or a field selector of an addressable struct operand; or an array indexing operation of an addressable array. As an exception to the addressability requirement, x may also be a (possibly parenthesized) composite literal.
If a S contains a *T, you don't even need to take its address so the methods can be called. If *S contains a T, you know T is addressable because T is a field selector of a pointer indirected struct. For S containing T, this cannot be guaranteed.
UPDATE: why does that code work?
Remember that *S contains the method set of *T. Also, as I quoted before:
If x is addressable and &x's method set contains m, x.m() is shorthand for (&x).m()
Put the two together and you have your answer. Counter is addressable and &counter contains the method set of *T. Therefore, counter.Inc() is shorthand for (&counter).Inc().
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With