指针新手 - 纠正我

时间:2016-11-23 00:21:50

标签: go

我还在学习,需要一只手来清理我的脑袋。

在每个Power中,程序输出1值为Println。我期待1作为第一输出,2作为第二输出。 我的假设是Change funcaddress 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}
}

Code

为了进一步探讨掩护下发生的事情,我这次尝试打印地址,看起来如下;

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
}

2 个答案:

答案 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对象,则需要将参数声明为Changes **pos,将函数中的赋值更改为{{ 1}},并致电*s = &Pod{2}。但这可能不是你想做的事。