From the Calls section of Go spec: https://golang.org/ref/spec#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()
My program.
package main
import (
"fmt"
)
func main() {
p := Point{2, 3}
p.FakeScale(10)
fmt.Println(p)
p.RealScale(10)
fmt.Println(p)
}
type Point struct {
x int
y int
}
func (p Point) FakeScale(s int) {
p.x *= s
p.y *= s
}
func (p *Point) RealScale(s int) {
p.x *= s
p.y *= s
}
Here is the output.
{2, 3}
{20, 30}
My question is specifically about this part of the spec.
If x
is addressable and &x
's method set contains m
, x.m()
is shorthand for (&x).m()
My questions.
- Is the quoted part applicable to
p.FakeScale(10)
? My guess is "No" because although p
is addressable, &p
's method set does not contain FakeScale
. p
's method set contains FakeScale
because it uses value receiver, but p
's method set does not contain FakeScale
, therefore this part of the spec is not applicable to p.FakeScale(10)
. Am I correct?
- Is the quoted part applicable to
p.RealScale(10)
? My guess is "Yes" because p
is addressable and &p
's method set contains RealScale
by virtue of it using a pointer receiver. Therefore, this part of the spec is applicable to p.RealScale(10)
. Am I correct?
- Can you provide an example code where
x.m()
is valid but x
is not addressable, and thus this part of the spec is not applicable?
Unfortunately, language lawyers have to read the entire specification to put a single sentence in context: The Go Programming Language Specification.
Method sets
A type may have a method set associated with it. The method set of an
interface type is its interface. The method set of any other type T
consists of all methods declared with receiver type T. 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). Further rules apply to structs containing anonymous fields,
as described in the section on struct types. Any other type has an
empty method set. 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.
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().
Address operators
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.
For example,
package main
import (
"fmt"
)
type Point struct {
x int
y int
}
func (p Point) FakeScale(s int) {
p.x *= s
p.y *= s
}
func (p *Point) RealScale(s int) {
p.x *= s
p.y *= s
}
func main() {
p := Point{2, 3}
p.FakeScale(10)
fmt.Println(p)
p.RealScale(10)
fmt.Println(p)
}
The method set of type Point consists of all methods declared with receiver type Point (FakeScale).
A method call p.FakeScale is valid since the method set of (the type of) p (Point) contains FakeScale and the argument list, (10), can be assigned to the parameter list, (int), of FakeScale.
The method set of type *Point consists of all methods declared with receiver type *Point (RealScale).
Since p is addressable (p is a variable) and &p's method set contains RealScale, p.RealScale() is shorthand for (&p).RealScale().
Also, see my answer to your earlier question: How to invoke a method with pointer receiver after type assertion?.
Hm. Also I begin to doubt my knowledge of English language but I will try to answer.
You quoted 2 sentences from specification.
- Describes conditions for method to be valid.
- Describes shorthand for recievers of pointer types.
Back to your question:
You defined 2 methods for 2 types: first - reciever of Point and second - receiver of pointer to Point.
Obviously, shorthand definition for pointer types is not applicable for non-pointer types.
So, you're correct in your questions 1 or 2.
And your third question is in fact question 1: FakeScale is valid method but method with non-pointer type in receiver, so shorthand definition is not applicable.