Consider the following code:
package main
import (
"fmt"
)
type Person struct {
Age int
M map[string]func()
}
func New() Person {
p := Person{1, make(map[string]func())}
p.M["1"] = p.Add
return p
}
func (p *Person) Add() {
fmt.Println("Age before mutating in Add", p.Age)
p.Age = 1 // here age should become 3
fmt.Println("Age after mutating in Add", p.Age)
}
func (p *Person) Run() {
fmt.Println("Age before mutating in Run", p.Age)
p.Age = 1 // here age should be 2
p.M["1"]()
fmt.Println("Age after mutating in Run", p.Age)
}
func main() {
p := New()
fmt.Println("age before", p.Age)
p.Run()
fmt.Println("age after", p.Age)
}
This produces output
age before 1
Age before mutating in Run 1
Age before mutating in Add 1
Age after mutating in Add 2
Age after mutating in Run 2
age after 2
Here M
is a map member of a struct, it stores methods of the same struct against strings.
In main we instantiate a non pointer struct value.
Then we call a method Run
on that struct which is defined to have a pointer receiver. This should share a pointer to the struct with the method, which should allow the method to mutate the original struct.
Within Run
we call the function Add
stored within the map, via the map. But this does not mutate the struct, in fact it seems to operate on the state of the object as it was when newly created.
Any changes within Add
are lost by the time Run
ends, although Add
is also declared with a pointer receiver.
I suspect this is because the original object was copied into the map somehow when calling p.M["1"] = p.Add
?
Why does calling the method with pointer receiver not mutate the object?
Playground link https://play.golang.org/p/CRer_rT8_sj
CodePudding user response:
New
returns a Person
and not a *Person
.
When you write
p := New()
it starts with New
constructing a Person pnew
and adding its Add method to pnew.M
. Then it returns pnew
.
Then this pnew
is assigned to p
which is a different variable. So p.M
contains now pnew
's Add method. When you execute p.M["1"]()
in Run pnew
's Age is incremented (which is unrelated to p
's age.