问题描述
我将一些个人对象存储在切片中。在将它附加到切片之前,我打印出 Individual 对象的名称。
在将它存储在切片,然后我将它检索为一个指针,并希望将其名称更改为Peter,但该更改不起作用,因为它仍然会打印史蒂夫。为什么?
类型单个接口{
GetName()*字符串
SetName(名称字符串)
}
类型Person结构{
名称字符串
}
//实现Individual接口的函数
func(p Person)GetName ()* string {
return& p.name
}
func(p Person)SetName(newName string){
name:= p.GetName( );
* name = newName
}
var individual [] Individual
func main(){
person:= Person {name:Steve}
fmt.Println(person)
个人=追加(个人,人)//追加人分片
p1:=个人[0 ] //获取片段中唯一的人
p1.SetName(Peter)//更改名称
fmt.Println(p1)//打印Peter,但打印Steve
fmt.Println(person)//打印Peter,但打印Steve
}
如果一个方法有一个非指针接收器,当该方法被调用时,将复制一个副本并传递。从这一点来说,不管你用接收器做什么,你只能修改副本,而不是原来的。
所以在你的例子中:
func(p Person)SetName(newName string){
name:= p.GetName();
* name = newName
}
当 SetName ()被调用,副本由 Person 组成。在 SetName()中获得副本的名称字段的地址,它你修改。 (实际上,拷贝副本,稍后更多......)
解决方案:使用指针接收器:
pre $ func(p * Person)SetName(newName string){
name:= p.GetName( );
* name = newName
}
从这时起,只有 * Person 实现 Individual ,因此在追加时使用指针:
个人=追加(个人和人)
棘手的,因为在此之后,窗台将无法工作。为什么会这样?
这是因为 Person.GetName()仍然有一个非指针接收者:
func(p Person)GetName()* string {
return& p.name
}
所以当 GetName() code> SetName(),一个副本将被重新创建,并且 GetName()将返回<$ c $ copy 的 字段以及 SetName()只会修改为调用<$ c创建的副本$ c $> GetName()。
因此,为了完成所有工作,您还必须使用 GetName指针接收器():
func(p * Person)GetName()* string {
返回& p.name
}
现在它正在运行,输出):
{Steve}
& {Peter}
{Peter}
但知道最简单和推荐的方法很简单:
p.name = newName
}
这就是所需要的。
I store some Individual objects in a slice. Before appending it to the slice I print the name of the Individual object.
After I have stored it in the slice, I then retrieve it as a pointer and want to change the name to "Peter", but the change does not work since it still prints "Steve". Why?
type Individual interface { GetName() *string SetName(name string) } type Person struct { name string } // Implement functions of the Individual interface func (p Person) GetName() *string { return &p.name } func (p Person) SetName(newName string) { name := p.GetName(); *name = newName } var individuals []Individual func main() { person := Person{name: "Steve"} fmt.Println(person) individuals = append(individuals, person) // append Person to slice p1 := individuals[0] // Retrieve the only Person from slice p1.SetName("Peter") // Change name fmt.Println(p1) // Should print "Peter", but prints "Steve" fmt.Println(person) // Should print "Peter", but prints "Steve" }
Whenever a method wants to modify the receiver, it must be a pointer to the value; the method must have a pointer receiver.
If a method has a non-pointer receiver, a copy will be made and passed when that method is called. From that point, no matter what you do with the receiver, you can only modify the copy, and not the original.
So in your example:
func (p Person) SetName(newName string) { name := p.GetName(); *name = newName }
When SetName() is called, a copy is made of the Person. Inside SetName() you obtain the address of the name field of the copy, which you modify. (Actually, a copy of the copy, more on this later...)
Solution: use a pointer receiver:
func (p *Person) SetName(newName string) { name := p.GetName(); *name = newName }
From this point on, only *Person implements Individual, so use a pointer when appending:
individuals = append(individuals, &person)
It's tricky, because after this it sill won't work. Why is that?
It is because the Person.GetName() still has a non-pointer receiver:
func (p Person) GetName() *string { return &p.name }
So when GetName() is called from SetName(), a copy will be made again, and GetName() will return the address of the name field of the copy, and SetName() will only modify the copy created for calling GetName().
So to make all work, you also have to use pointer receiver for GetName():
func (p *Person) GetName() *string { return &p.name }
And now it's working, output (try it on the Go Playground):
{Steve} &{Peter} {Peter}
But know that the easiest and recommended way is simply:
func (p *Person) SetName(newName string) { p.name = newName }
That's all it takes.
这篇关于即使我使用指向类型的指针来更新它,我的对象也不会更新(Golang)的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!