即使我使用指向类型的指针来更新它,我的对象也不会更新 [英] My object is not updated even if I use the pointer to a type to update it

查看:66
本文介绍了即使我使用指向类型的指针来更新它,我的对象也不会更新的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我在切片中存储了一些Individual对象.在将其附加到切片之前,我先打印Individual对象的名称.

I store some Individual objects in a slice. Before appending it to the slice I print the name of the Individual object.

将其存储在切片中之后,我将其检索为指针,并希望将其名称更改为"Peter",但是该更改不起作用,因为它仍会打印"Steve".为什么?

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.

在您的示例中:

func (p Person) SetName(newName string)  {
    name := p.GetName();
    *name = newName
}

调用SetName()时,将复制Person.在SetName()内部,您获取要修改的副本name字段的地址. (实际上,是该副本的副本,稍后会详细介绍...)

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
}

从现在开始,只有*Person实现Individual,因此在添加时使用指针:

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?

这是因为Person.GetName()仍然具有非指针接收器:

It is because the Person.GetName() still has a non-pointer receiver:

func (p Person) GetName() *string {
    return &p.name
}

因此,当从SetName()调用GetName()时,将再次进行复制,并且GetName()将返回副本name字段的地址,以及只会修改为调用GetName()而创建的副本.

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().

因此,要使所有工作正常进行,还必须对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
}

仅此而已.

这篇关于即使我使用指向类型的指针来更新它,我的对象也不会更新的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
相关文章
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆