即使我使用指向类型的指针来更新它,我的对象也不会更新

时间:2017-05-10 11:07:31

标签: pointers go methods slice

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

将其存储在切片中后,我将其作为指针检索,并希望将名称更改为"Peter",但由于仍然打印"Steve",因此更改无效。为什么?

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"
}

3 个答案:

答案 0 :(得分:5)

每当方法想要修改接收器时,它必须是指向值的指针;该方法必须有一个指针接收器。

如果方法具有非指针接收器,则在调用该方法时将生成并传递副本。从那时起,无论您使用接收器做什么,都只能修改副本,而不能修改原始副本。

所以在你的例子中:

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

调用SetName()时,会复制Person。在SetName()内,您可以获得修改后的副本name字段的地址。 (实际上,副本的副本,稍后会详细介绍......)

解决方案:使用指针接收器:

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

从现在开始,只有*Person实现了Individual,所以在追加时使用指针:

individuals = append(individuals, &person)

这很棘手,因为在此之后它会起作用。那是为什么?

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

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

因此,当从GetName()调用SetName()时,将再次制作副本,GetName()将返回副本的name字段的地址SetName()只会修改为调用GetName()而创建的副本。

因此,为了完成所有工作,您还必须使用GetName()的指针接收器:

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

现在它正在工作,输出(在Go Playground上试试):

{Steve}
&{Peter}
{Peter}

但要知道最简单和推荐的方法就是:

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

这就是全部。

答案 1 :(得分:3)

要解决此问题的两件事:

  • 您需要通过“指针”方法附加方法,否则仅在方法内更改名称。
  • 您需要使用实际Person变量的指针,因为它们需要实现接口
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)  {
    p.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)          // Prints "Steve"
    fmt.Println(person)      // Prints "Steve"
}

Go Playground上的示例。

答案 2 :(得分:0)

请参阅https://play.golang.org/p/eg8oYDV6Xx p1和p2已经是地址,您不需要他们的地址(地址),只需打印p1和p2 - 它们将与您看到的相同。