Reputation: 67
I want to know whats the difference of having methods on pointer and method on values. How both the methods work on standard structure instance as well as structure pointer.
Upvotes: 5
Views: 1463
Reputation: 24866
Format:
func (r T) Xxx() {}
Could call by either a value or a pointer.
When call with pointer, the value will be passed automatically, (it actually use *
to get value of the caller, and pass it).
Format:
func (r *T) Xxx() {}
In principle, should invoke with pointer only, but that's not necessary.
Because when call with value, instead of pointer, compiler will take care of it, when possible:
&
), and pass it automatically.map
's element is not addressable.Pointer caller is preferred, when define a method, if proper.
Reasons:
What is passed to method, depends on the method signature, not how you call it (this is similar as with param).
(r *T)
, it pass pointer.(r T)
, it pass a copy of original caller.T
itself can't be pointer.And, here is a go code that I wrote when learning this feature.
Its 2 functions called in main()
tests the 2 features respectively.
method_learn.go:
// method - test
package main
import (
"fmt"
"math"
)
type Vertex struct {
x float64
y float64
}
// abs, with pointer caller,
func (v *Vertex) AbsPointer() float64 {
return math.Sqrt(v.x*v.x + v.y*v.y)
}
// scale, with pointer caller,
func (v *Vertex) ScalePointer(f float64) *Vertex {
v.x = v.x * f
v.y = v.y * f
return v
}
// abs, with value caller,
func (v Vertex) AbsValue() float64 {
return math.Sqrt(v.x*v.x + v.y*v.y)
}
// test - method with pointer caller,
func pointerCallerLearn() {
vt := Vertex{3, 4}
fmt.Printf("Abs of %v is %v. (Call %s method, with %s)\n", vt, vt.AbsPointer(), "pointer", "value") // call pointer method, with value,
fmt.Printf("Abs of %v is %v. (Call %s method, with %s)\n\n", vt, (&vt).AbsPointer(), "pointer", "pointer") // call pointer method, with pointer,
// scala, change original caller,
fmt.Printf("%v scale by 10 is: %v (Call %s method, with %s)\n", vt, vt.ScalePointer(10), "pointer", "value") // call pointer method, with value,
fmt.Printf("%v scale by 10 is: %v (Call %s method, with %s)\n", vt, (&vt).ScalePointer(10), "pointer", "pointer") // call pointer method, with pointer,
}
// test - method with value caller,
func valueCallerLearn() {
vt := Vertex{3, 4}
fmt.Printf("Abs of %v is %v. (Call %s method, with %s)\n", vt, (&vt).AbsValue(), "value", "pointer") // call value method, with pointer,
fmt.Printf("Abs of %v is %v. (Call %s method, with %s)\n", vt, vt.AbsValue(), "value", "value") // call value method, with value,
}
func main() {
// pointerCallerLearn()
valueCallerLearn()
}
Just modify main()
, and run via go run method_test.go
, then check the output to see how it works.
Upvotes: 6
Reputation: 230276
The big difference between them is that value receivers are copied*. So if you want to mutate your receiver, you have to use pointer. Observe:
package main
import (
"fmt"
)
type Person struct {
Age int
}
func (p Person) GrowUp1() {
p.Age++
}
func (p *Person) GrowUp2() {
p.Age++
}
func main() {
p := Person{Age: 20}
fmt.Println(p)
p.GrowUp1()
fmt.Println(p)
p.GrowUp2()
fmt.Println(p)
}
// {20}
// {20}
// {21}
* Pointers are copied too, naturally. But since they're pointers, a copy of a pointer still points to the same object.
Upvotes: 2