我在切片中存储了一些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"
}
答案 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 - 它们将与您看到的相同。