方法接收者是否作为指针之间的区别

Why don't I have to define PrintValue() as a pointer receiver (*One) to be able to print "hello"?

package main
import "fmt"


type One struct{
    a string
}
func (o *One)AssignValue(){
    o.a = "hello"
}
func (o One)PrintValue(){
    fmt.Println(o.a)
}

func main() {
    one := One{}
    one.AssignValue()
    one.PrintValue()
}

Because one is already of type One. The instantiation syntax

t := One{}

creates a value of type One while the form

p := &One{}

creates a pointer to a value of type One.

This means that nothing is to be done when calling t.PrintValue as the receiver type (One) is already the same as the type of t (One as well).

When calling p.PrintValue the compiler automatically converts an addressable variable to its pointer form because the receiver type (One) is not equal to the type of p (*One). So the expression

p.PrintValue()

is converted to

(*p).PrintValue()

There is also a conversion necessary when calling t.AssignValue as this method has a pointer receiver but we're supplying a value. This is also done automatically by the compiler where possible.

From the spec on 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()

This means the expression

t.AssignValue()

is converted to

(&t).AssignValue()

Note that this is not always possible. For example when returning a value from a function:

func NewOne(s string) One { return One{s} }

NewOne("foo").AssignValue() // Not possible

x := NewOne("foo")
x.AssignValue() // Possible, automatically converted