即使我使用指向类型的指针来更新它,我的对象也没有更新
Posted
技术标签:
【中文标题】即使我使用指向类型的指针来更新它,我的对象也没有更新【英文标题】:My object is not updated even if I use the pointer to a type to update it 【发布时间】:2017-10-08 23:56:48 【问题描述】:我将一些 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 := Personname: "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"
【问题讨论】:
【参考方案1】:解决这个问题的两件事:
您需要通过“指针”方法附加方法,否则名称只会在方法内部更改。 您需要为实际的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 := &Personname: "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 上的示例。
【讨论】:
就目前而言,我认为GetName
有点误导。它在Person
的副本中返回指向string
的指针。我假设该方法应该有一个指针接收器或按值返回,不是吗?【参考方案2】:
每当一个方法想要修改接收者时,必须是指向值的指针;该方法必须有一个指针接收器。
如果一个方法有一个非指针接收器,则在调用该方法时会生成并传递一个副本。从那时起,无论你对接收者做什么,你都只能修改副本,而不能修改原件。
所以在你的例子中:
func (p Person) SetName(newName string)
name := p.GetName();
*name = newName
当调用SetName()
时,会复制Person
。在SetName()
中,您将获得您修改的copy 的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
所以当从SetName()
调用GetName()
时,会再次进行复制,GetName()
会返回copy的name
字段的地址,@987654338 @ 只会修改为调用 GetName()
而创建的副本。
因此,为了使所有工作正常进行,您还必须为GetName()
使用指针接收器:
func (p *Person) GetName() *string
return &p.name
现在它正在工作,输出(在Go Playground 上试试):
Steve
&Peter
Peter
但要知道,最简单和推荐的方法很简单:
func (p *Person) SetName(newName string)
p.name = newName
仅此而已。
【讨论】:
我认为GetName
按值返回string
会更惯用?
感谢您的好评!如果我多次调用p1 := individuals[0]
,然后在每次调用后用fmt.Println(&p1)
打印地址,我每次都会得到不同的地址。 p2 := individuals[0]
然后fmt.Println(&p2)
将打印另一个地址。为什么?
@ChrisDrew 是的,很明显。我只是想从代码中引导提问者提供的内容,因为我认为它具有启发性/启发性(copy of copy 部分并非不言而喻)。
@Rox p1 := individuals[0]
是一个 short variable declaration,它创建了一个局部变量,&p1
是 局部变量 的地址(而不是指针值应该它包含一个指针),每次都会(可能)不同。【参考方案3】:
见https://play.golang.org/p/eg8oYDV6Xx p1 和 p2 已经是地址,你不需要它们的地址(地址的地址),只需打印 p1 和 p2 - 它们会和你看到的一样。
【讨论】:
以上是关于即使我使用指向类型的指针来更新它,我的对象也没有更新的主要内容,如果未能解决你的问题,请参考以下文章