receiver's usage
package main
import "fmt"
type Person struct {
name string
age int
}
func (p *Person) greeting1() {
fmt.Println(p) //&{0}
fmt.Println(&p) //0xc000086018
fmt.Println("Hello~")
}
func (p Person) greeting2() {
fmt.Println(p) //{0}
fmt.Println(&p) //&{0}
fmt.Println("Hello~")
}
type Student struct {
//p Persion -> has a
Person // -> is a
school string
grade int
}
func test1(p Student) {
fmt.Println(p)
}
func test2(p *Student){
fmt.Println(p)
}
func main() {
var s Student
//s.p.greeting()
s.greeting1()
s.greeting2()
test1(s)
//test2(s) -> error
}
When I use function in golang, If I declare value variable, when I use function I made, I had to put only value variable on paramter. like,
a int= 10;
func func1(param int){
fmt.Println(fmt)
}
despite I declared Person as a value struct in Student struct, as you see my code, receiver functions(greeting1, greeting2) are getting two type parameters which are *Person, and Person. I cannot understand that why greeting1 function is functioning without error, despite I put value variable as a parameter. Thank you for you guys help.
Simplifying your example code to focus on the question / issue at hand:
package main
import "fmt"
type Person struct {
name string
age int
}
func (p *Person) greeting1() {
fmt.Println(p)
fmt.Println(&p)
}
func main() {
var p Person
p.name = "joe"
p.age = 41
p.greeting1()
}
Prints:
&{joe 41}
0xc00000c028
In short, the call p.greeting1()
works because Go sees that Person
(the type of p
) has a greeting1
method defined on a pointer receiver. So it treats the call p.greeting1()
as equivalent to (&p).greeting1()
. As mkopriva said in a comment, this is clearly laid out in the Go spec:
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 is done for convenience. Since pointer receivers are quite necessary and popular in Go - you need them whenever your method mutates the underlying object - it helps write cleaner code. You shouldn't be forced to write (&p).greeting1()
where p.greeting1()
would do - this substituion is unambiguous as the compiler knows what methods are defined on Person
, and with which receivers.
Effective Go has a section on pointer vs. value receivers that you should read. Here's one relevant quote:
When the value is addressable, the language takes care of the common case of invoking a pointer method on a value by inserting the address operator automatically. In our example, the variable b is addressable, so we can call its Write method with just b.Write. The compiler will rewrite that to (&b).Write for us.
Actually Go is an object oriented language in its own way. It uses struct instead of classes. If you want to have a class, you must make a struct and relate some funcs to it by a pointer of that struct, So later you can create many independent object from your struct. You can use the function new which will return a pointer of your struct. Like:
p:=new(person)
p.name = "joe"
p.age = 41
p.greeting1()