我从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 不会更改调用者的值。
为什么会发生这种情况,为什么与 3rd 和 4th 不同?
答案 0 :(得分:3)
要记住的关键是,所有内容都是通过值传递的(也就是通过复制传递)。当您将指针传递给函数时,该参数是该函数中的 still 一个局部变量,其中包含指针的副本。该本地副本指向调用者引用的相同内存。
执行此操作时:
v = &User{Name: "Paul"}
您正在使用指向v
的 new 实例的 new 指针覆盖局部变量 User
。现在它指向的内存与调用方的指针不同,因此调用方看不到任何内容。
如果您改为这样做:
*v = User{Name: "Paul"}
然后指向 same 内存的 same 指针将被User
的 new 实例覆盖。 / p>
同样,在Modify3
中,您有一个指向指针的指针。因此,您的调用者和函数每个都有一个局部变量,该局部变量指向一个存储位置,该存储位置保存另一个可以找到实际值的存储位置。请注意,这是Go语言中非常不常见(但并非闻所未闻)的模式,但在其他语言中却很常见。当您这样做时:
*y = &User{Name: "Bob"}
您正在创建指向新User
的新指针,并将该新指针存储在外部指针所指向的共享内存中。因此,再次,函数和调用者都共享内存,并且两者都将看到更改。