doq70020 2016-11-23 00:21
浏览 25
已采纳

指针新手-纠正我

I am still learning go and need a hand to clear my head.

Following program output Power value as 1 in each Println. I was expecting 1 as first output and 2 as second output. My assumption was the Change func overwrite the address of s with anew address and this change will reflect back to the caller (main func). In such case, the original address would be pointing to newly created address when it call the second Println. My assumption is wrong but I can't figure out why.

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

To explore further on what happens under cover, I did tried to print addresses this time and it looks like below;

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条回答 默认 最新

  • dongqing8765 2016-11-23 01:00
    关注

    It's because when you pass arguments to functions etc, they are always passed by value.

    In other words, even though you are accepting a pointer in the function parameter, the address of the struct will be copied.

    Then when you assign to s to try and change the address it only changes that local copy, not the one outside the function.

    To change the address from within the function you would need to pass in a pointer pointer, then assign to the dereferenced s, for example:

    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}
    }
    

    In this case a copy of an address is still being passed into the function, but because it's a pointer to a pointer it means that when you dereference s as *s you will get the address of the struct outside of the function. This means if you assign to *s you can change the address of the pointer outside the function.

    Of course, like Andy Schweig says, you probably wouldn't really want to do that though, and would probably just change individual fields as needed with the normal pointer version of the function.

    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
    }
    

    This works because when you type s.Power = 2 Go will actually do something like (*s).Power = 2 for you. So it automatically dereferences s for you which gives you the actual Pod struct to work with.

    You can't do *s = &Pod{2} in this normal pointer example because in that case *s will actually equal type Pod, not *Pod.

    Because of that if you want to use the &Pod{2} syntax to assign an address you need to pass a pointer to the pointer. In the case of s **Pod the dereferenced *s will point to the address of the Pod instead of the actual Pod, so *s will be of type *Pod which allows you to assign &Pod{2}.

    Having said all of that, a **Pod is only required if you want to assign an address with the &Pod{2} syntax.

    If you don't need to use the &Pod{2} syntax you can just dereference s and assign with a normal 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}
    }
    

    This also works, because now s is a copy of an address, and when you dereference you get to the value outside the function which is type Pod, not *Pod.

    That means you can just assign to it by removing the &.

    Basically if you use & it means you want to assign an address rather than the actual value.

    I hope this explanation isn't too confusing. I explained using a **Pod because I thought you wanted to use the &Pod{2} syntax rather than Pod{2}, but if that's not the case then my s.Power = 2 or *s = Pod{2} examples may make more sense.

    本回答被题主选为最佳回答 , 对您是否有帮助呢?
    评论
查看更多回答(1条)

报告相同问题?

悬赏问题

  • ¥15 c语言怎么用printf(“\b \b”)与getch()实现黑框里写入与删除?
  • ¥20 怎么用dlib库的算法识别小麦病虫害
  • ¥15 华为ensp模拟器中S5700交换机在配置过程中老是反复重启
  • ¥15 java写代码遇到问题,求帮助
  • ¥15 uniapp uview http 如何实现统一的请求异常信息提示?
  • ¥15 有了解d3和topogram.js库的吗?有偿请教
  • ¥100 任意维数的K均值聚类
  • ¥15 stamps做sbas-insar,时序沉降图怎么画
  • ¥15 买了个传感器,根据商家发的代码和步骤使用但是代码报错了不会改,有没有人可以看看
  • ¥15 关于#Java#的问题,如何解决?