Указатели и ссылки на структуру в функциях - PullRequest
0 голосов
/ 31 января 2019

Я начинаю с Go и испытываю трудности с пониманием указателей и ссылок на структуры внутри функций.

С учетом примера 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)
}

Результаты:

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

Кроме примера 1st , где у меня нет вопросов, все остальные, кажется, указывают на исходное присвоение структуры, но 2nd не меняет значение вызывающей стороны,

Почему это происходит и почему это отличается от 3-го и 4-го ?

1 Ответ

0 голосов
/ 31 января 2019

Ключевым моментом, который следует помнить, является то, что все передается по значению (то есть, копируется).Когда вы передаете указатель на функцию, этот параметр является все еще локальной переменной в этой функции, содержащей копию указателя .Эта локальная копия указывает на ту же память, на которую ссылается вызывающая сторона.

Когда вы делаете это:

v = &User{Name: "Paul"}

Вы перезаписываете свою локальную переменную v новый указатель на новый экземпляр User.Теперь он указывает на память, отличную от указателя вызывающего, поэтому вызывающий ничего не видит.

Если вы вместо этого сделали это:

*v = User{Name: "Paul"}

Затем указатель тот же , указывающийв ту же память, будет перезаписан новым экземпляром User.

Аналогично, в Modify3 у вас есть указатель науказатель .Таким образом, у вашего вызывающего и функции есть локальная переменная, которая указывает на область памяти, которая содержит другую область памяти, где можно найти фактическое значение.Обратите внимание, что это очень необычный (но не неслыханный) шаблон в Go, но распространенный в других языках.Когда вы делаете это:

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

Вы создаете новый указатель на новый User и сохраняете этот новый указатель в общей памяти, на которую указывает внешний указатель.Итак, опять же, и функция, и вызывающая сторона делят память, и оба увидят изменения.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...