dpzp5127 2019-01-31 14:55
浏览 57
已采纳

函数中结构的指针和引用

I'm starting with Go and I'm having difficulty understanding pointers and references to structs inside functions.

Considering the example https://play.golang.org/p/zd8La4ecNXw

package main

import "fmt"

type User struct {
  Name string
}

func main() {
  // 1st
  u := User{Name: "Anne"}
  fmt.Println("1st: ", &u.Name)
  fmt.Println("1st: ", u.Name)
  Modify1(u)
  fmt.Println("1st: ", u.Name)

  // 2nd
  fmt.Println()
  v := &User{Name: "Anne"}
  fmt.Println("2nd: ", &v.Name)
  fmt.Println("2nd: ", v.Name)
  Modify2(v)
  fmt.Println("2nd: ", v.Name)

  // 3rd
  fmt.Println()
  y := &User{Name: "Anne"}
  fmt.Println("3rd: ", &y.Name)
  fmt.Println("3rd: ", y.Name)
  Modify3(&y)
  fmt.Println("3rd: ", y.Name)

  // 4th
  fmt.Println()
  z := &User{Name: "Anne"}
  fmt.Println("4th: ", &z.Name)
  fmt.Println("4th: ", z.Name)
  Modify4(z)
  fmt.Println("4th: ", z.Name)
}

func Modify1(u User) {
  fmt.Println("func: ", &u.Name)
  u.Name = "Duncan"
  fmt.Println("func: ", u.Name)
}

func Modify2(v *User) {
  fmt.Println("func: ", &v.Name)
  v = &User{Name: "Paul"}
  fmt.Println("func: ", v.Name)
}

func Modify3(y **User) {
  fmt.Println("func: ", &y)
  fmt.Println("func: ", &(*y).Name)
  *y = &User{Name: "Bob"}
  fmt.Println("func: ", (*y).Name)
}

func Modify4(z *User) {
  fmt.Println("func: ", &z.Name)
  z.Name = "John"
  fmt.Println("func: ", z.Name)
}

Results:

1st:  0x40e128
1st:  Anne
func:  0x40e140
func:  Duncan
1st:  Anne

2nd:  0x40e158
2nd:  Anne
func:  0x40e158
func:  Paul
2nd:  Anne

3rd:  0x40e188
3rd:  Anne
func:  0x40e198
func:  0x40e188
func:  Bob
3rd:  Bob

4th:  0x40e1b8
4th:  Anne
func:  0x40e1b8
func:  John
4th:  John

Apart from the 1st example, where Ihave no questions, all the others seem to point to the original struct assignment, but 2nd doesn't change the caller value.

Why does this happen, and why is this different than in 3rd and 4th?

  • 写回答

1条回答 默认 最新

  • donglu9898 2019-01-31 15:48
    关注

    The key thing to remember is that everything is passed by value (a.k.a. passed by copying). When you pass a pointer to a function, that parameter is still a local variable in that function, containing a copy of the pointer. That local copy points to the same memory referenced by the caller.

    When you do this:

    v = &User{Name: "Paul"}
    

    You're overwriting your local variable v with a new pointer to a new instance of User. It now points to different memory than the caller's pointer, so the caller sees nothing.

    If you instead did this:

    *v = User{Name: "Paul"}
    

    Then the same pointer, pointing to the same memory, would be overwritten with a new instance of User.

    Likewise, in Modify3, you have a pointer to a pointer. So your caller and function each have a local variable, which points to a memory location, which holds another memory location, where an actual value can be found. Note that this is a very unusual (but not unheard of) pattern in Go, but common in other languages. When you do this:

    *y = &User{Name: "Bob"}
    

    You're creating a new pointer to a new User, and storing that new pointer in the shared memory pointed to by the outer pointer. So, again, both function and caller are sharing memory and both will see the changes.

    本回答被题主选为最佳回答 , 对您是否有帮助呢?
    评论

报告相同问题?