英文:
Why does object state not change when calling methods with a pointer receiver from within a map?
问题
考虑以下代码:
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("在 Add 中修改前的年龄:", p.Age)
p.Age += 1 // 这里年龄应该变为 3
fmt.Println("在 Add 中修改后的年龄:", p.Age)
}
func (p *Person) Run() {
fmt.Println("在 Run 中修改前的年龄:", p.Age)
p.Age += 1 // 这里年龄应该是 2
p.M["1"]()
fmt.Println("在 Run 中修改后的年龄:", p.Age)
}
func main() {
p := New()
fmt.Println("调用 Run 前的年龄:", p.Age)
p.Run()
fmt.Println("调用 Run 后的年龄:", p.Age)
}
这段代码的输出结果是:
调用 Run 前的年龄: 1
在 Run 中修改前的年龄: 1
在 Add 中修改前的年龄: 1
在 Add 中修改后的年龄: 2
在 Run 中修改后的年龄: 2
调用 Run 后的年龄: 2
在这里,M
是结构体的一个映射成员,它存储了相同结构体的方法,并与字符串关联。
在 main
函数中,我们实例化了一个非指针的结构体值。
然后我们在该结构体上调用了一个名为 Run
的方法,该方法被定义为具有指针接收器。这应该与该方法共享指向结构体的指针,从而允许该方法修改原始结构体。
在 Run
方法内部,我们通过映射调用了存储在映射中的 Add
函数。但是这并没有修改结构体,实际上它似乎是在新创建时的对象状态上操作的。
在 Run
结束时,Add
中的任何更改都会丢失,尽管 Add
也是使用指针接收器声明的。
我怀疑这是因为在调用 p.M["1"] = p.Add
时,原始对象被某种方式复制到了映射中?
为什么使用指针接收器调用方法不会修改对象呢?
Playground 链接:https://play.golang.org/p/CRer_rT8_sj
英文:
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
答案1
得分: 3
New
返回的是一个 Person
而不是 *Person
。
当你写下
p := New()
它首先通过 New
构造一个名为 pnew
的 Person
,并将其 Add
方法添加到 pnew.M
中。然后它返回 pnew
。
然后将这个 pnew
赋值给 p
,它是一个 不同的 变量。所以 p.M
现在包含了 pnew
的 Add
方法。当你执行 p.M["1"]()
时,在 Run
中 pnew
的 Age
会增加(这与 p
的年龄无关)。
英文:
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.
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论