我还在学习,需要一只手来清理我的脑袋。
在每个Power
中,程序输出1
值为Println
。我期待1
作为第一输出,2
作为第二输出。
我的假设是Change
func
用address of
覆盖s
new address
,此更改将反映给调用方(main func
)。在这种情况下,原始地址在调用第二个Println
时将指向新创建的地址。
我的假设是错误的,但我无法弄清楚原因。
package main
import (
"fmt"
)
type Pod struct{
Power int
}
func main() {
pod := &Pod{1}
fmt.Println(pod.Power)
Change(pod)
fmt.Println(pod.Power)
}
func Change(s *Pod) {
s = &Pod{2}
}
为了进一步探讨掩护下发生的事情,我这次尝试打印地址,看起来如下;
import (
"fmt"
)
type Pod struct{
Power int
}
func main() {
pod := &Pod{ 1}
fmt.Println(&pod) //0xc04202c020
Change(pod)
fmt.Println(&pod) //0xc04202c020
}
func Change(s *Pod) {
fmt.Println(&s) //0xc04202c030 ( I was expecting 0xc04202c020 here)
s = &Pod{ 2}
fmt.Println(&s) //0xc04202c030
}
答案 0 :(得分:4)
这是因为当您将参数传递给函数等时,它们总是按值传递。
换句话说,即使您接受函数参数中的指针,也会复制结构的地址。
然后,当您指定s
尝试更改地址时,它只会更改本地副本,而不是功能之外的副本。
要从函数中更改您需要传入指针指针的地址,然后分配给解除引用的s
,例如:
package main
import (
"fmt"
)
type Pod struct {
Power int
}
func main() {
pod := &Pod{1}
fmt.Println(pod.Power)
Change(&pod)
fmt.Println(pod.Power)
}
func Change(s **Pod) {
*s = &Pod{2}
}
在这种情况下,地址的副本仍然被传递到函数中,但因为它是指向指针的指针,这意味着当您将s
取消引用为*s
时,您将获得函数外部的struct的地址。这意味着如果您分配给*s
,您可以在函数外部更改指针的地址。
当然,就像Andy Schweig所说,你可能不会真的想这样做,并且可能只是根据需要用函数的正常指针版本来改变单个字段。
package main
import (
"fmt"
)
type Pod struct {
Power int
}
func main() {
pod := &Pod{1}
fmt.Println(pod.Power)
Change(pod)
fmt.Println(pod.Power)
}
func Change(s *Pod) {
s.Power = 2
}
这是有效的,因为当您输入s.Power = 2
时,Go会为您执行类似(*s).Power = 2
的操作。因此,它会自动为您解除引用s
,从而为您提供实际的Pod
结构。
在此正常指针示例中,您无法*s = &Pod{2}
,因为在这种情况下,*s
实际上等于Pod
类型,而不是*Pod
。
因此,如果要使用&Pod{2}
语法分配地址,则需要将指针传递给指针。对于s **Pod
,解除引用的*s
将指向Pod
的地址而不是实际的Pod
,因此*s
的类型为{*Pod
1}}允许您分配&Pod{2}
。
说完所有这些后,只有在您想要使用**Pod
语法分配地址时才需要&Pod{2}
。
如果您不需要使用&Pod{2}
语法,则可以取消引用s
并使用正常Pod{2}
进行分配。
package main
import (
"fmt"
)
type Pod struct {
Power int
}
func main() {
pod := &Pod{1}
fmt.Println(pod.Power)
Change(pod)
fmt.Println(pod.Power)
}
func Change(s *Pod) {
*s = Pod{2}
}
这也有效,因为现在s
是地址的副本,当您取消引用时,您将获得类型为Pod
的函数外的值,而不是*Pod
。< / p>
这意味着您只需删除&
。
基本上,如果您使用&
,则表示您想要分配地址而不是实际值。
我希望这个解释不会太混乱。我使用**Pod
进行了解释,因为我认为您希望使用&Pod{2}
语法而不是Pod{2}
,但如果情况并非如此,那么我的s.Power = 2
或{ {1}}示例可能更有意义。
答案 1 :(得分:2)
将参数值更改为函数内的函数永远不会影响调用者传递的参数。所有参数都按值传递。如果要更改Power
(调用方中的s
)所指向的对象内pod
的值,请使用s.Power = 2
。如果您确实希望将调用者中的指针变量设置为不同的Pod
对象,则需要将参数声明为Change
为s **pos
,将函数中的赋值更改为{{ 1}},并致电*s = &Pod{2}
。但这可能不是你想做的事。