为什么当我们使用(* structObj)引用struct时,golang似乎返回structObj的新副本而不是返回原始structObj的相同地址?可能会对此产生一些误解,所以要求善意澄清
package main
import (
"fmt"
)
type me struct {
color string
total int
}
func study() *me {
p := me{}
p.color = "tomato"
fmt.Printf("%p\n", &p.color)
return &p
}
func main() {
p := study()
fmt.Printf("&p.color = %p\n", &p.color)
obj := *p
fmt.Printf("&obj.color = %p\n", &obj.color)
fmt.Printf("obj = %+v\n", obj)
p.color = "purple"
fmt.Printf("p.color = %p\n", &p.color)
fmt.Printf("p = %+v\n", p)
fmt.Printf("obj = %+v\n", obj)
obj2 := *p
fmt.Printf("obj2 = %+v\n", obj2)
}
输出
0x10434120
&p.color = 0x10434120
&obj.color = 0x10434140 //different than &p.color!
obj = {color:tomato total:0}
p.color = 0x10434120
p = &{color:purple total:0}
obj = {color:tomato total:0}
obj2 = {color:purple total:0} // we get purple now when dereference again
答案 0 :(得分:11)
不,“赋值”总是在Go中创建一个副本,包括赋值给函数和方法参数。声明obj := *p
将*p
的值复制到obj
。
如果您将语句p.color = "purple"
更改为(*p).color = "purple"
,您将获得相同的输出,因为解除引用p
本身不会创建副本。
答案 1 :(得分:8)
写作时
obj := *p
您正在复制p
指向的struct的值(*
dereferences p
)。它类似于:
var obj me = *p
因此obj
是me
类型的新变量,初始化为*p
的值。这会导致obj
拥有不同的内存地址。
请注意,obj
属于me
类型,而p
属于*me
类型。但它们是不同的价值观。更改obj
字段的值不会影响p
中该字段的值(除非me
结构中的引用类型为字段,即切片,地图或渠道。请参阅here和here。)。如果您想实现这种效果,请使用:
obj := p
// equivalent to: var obj *me = p
现在obj
指向与p
相同的对象。它们本身仍然具有不同的地址,但在其中包含实际me
对象的相同地址。
答案 2 :(得分:1)
tl; dr 在Go中取消引用(使用*
运算符)不会产生副本。它返回指针指向的原始值。