在Go语言中,通过将指针传递给函数可以获取不同的值。

huangapple go评论87阅读模式
英文:

Getting different values by passing Pointers to a function in Go

问题

假设我想通过传递一个指向结构体的指针来改变该指针所指向的结构体的值。通常情况下,我会通过解引用指针来实现:

type Test struct { Value int}
func main() {
   var i Test = Test {2}
   var p *Test = &i
   f(p)
   println(i.Value)  // 4
}
func f(p *Test) {
   *p = Test{4}
}

我的问题是,为什么这段代码没有改变值:

type Test struct { Value int}
func main() {
   var i Test = Test {2}
   var p *Test = &i
   f(p)
   println(i.Value)  // 2
}
func f(p *Test) {
   // ?
   p = &Test{4}
}

而这段代码却改变了值:

type Test struct { Value int}
func main() {
   var i Test = Test {2}
   var p *Test = &i
   f(p)
   println(i.Value)  // 4
}
func f(p *Test) {
   p.Value = 4
}
英文:

Say I want to pass a pointer to a function and change the value of a struct which that pointer points to by doing so. I would normally do this by dereferencing the pointer:

type Test struct { Value int}
func main() {
   var i Test = Test {2}
   var p *Test = &i
   f(p)
   println(i.Value)  // 4
}
func f(p *Test) {
   *p = Test{4}
}

My question is, why this code doesn't change the value

type Test struct { Value int}
func main() {
   var i Test = Test {2}
   var p *Test = &i
   f(p)
   println(i.Value)  // 2
}
func f(p *Test) {
   // ?
   p = &Test{4}
}

while this one does:

type Test struct { Value int}
func main() {
   var i Test = Test {2}
   var p *Test = &i
   f(p)
   println(i.Value)  // 4
}
func f(p *Test) {
   p.Value = 4
}

答案1

得分: 12

因为这行代码:

p = &Test{4}

只是将一个新的指针值赋给了变量 p。在 f() 函数内部,p 只是一个局部变量。通过给 p 赋任何新值,你只是改变了局部变量的值,而不是指向的值。

f() 函数中的局部变量 pmain() 函数中的局部变量 p 没有任何关系。如果你在 f() 中改变了 p,它不会改变 main() 中的 p(也不会改变指向的结构体值)。

在你的第二个例子中:

p.Value = 4

这是一种简写形式:

(*p).Value = 4

这会改变指向的值,因此当 f() 返回时,你会观察到这个变化。

注意:

顺便提一下,如果在你的 main() 函数中将 pmain() 中的局部变量,它是一个指针)的地址传递给函数 f(),你可以修改 main 中存储的 p 的地址:

func f(p **Test) {
    *p = &Test{4}
}

然后在 main() 中这样调用它:

var i Test = Test{2}
var p *Test = &i
f(&p)
println(i.Value) // 2 - 注意,'i' 不会改变!
println(p.Value) // 4 - 只有 'p' 中的地址指向了在 f() 中创建的新结构体值

但显然,传递一个单一指针 *Test 并修改指向的值(p.Value = 4)更高效、更方便、更清晰。

英文:

Because this line:

p = &Test{4}

Just assigns a new pointer value to the p variable. Inside the f() function, p is just a local variable. By assigning any new value to p, you are just changing the value of the local variable and not the pointed value.

The p local variable in f() has nothing to do with the p local variable in main(). If you change p in f(), it will not change p in main() (and it won't change the pointed struct value either).

In your second example:

p.Value = 4

It is a shorthand for:

(*p).Value = 4

This changes the pointed value, hence you will observe the change when f() returns.

Note:

Just as a side note, if in your main() function you would pass the address of p (the local variable in main() which is a pointer) to function f(), you could modify the address stored in main's p:

func f(p **Test) {
	*p = &Test{4}
}

And from main(), call it like:

var i Test = Test{2}
var p *Test = &i
f(&p)
println(i.Value) // 2 - Note that 'i' won't change!
println(p.Value) // 4 - Only the address in 'p' to the new struct value created in f()

But obviously passing a single pointer *Test and modifying the pointed value (p.Value = 4) is more efficient, much more convenient and much cleaner.

huangapple
  • 本文由 发表于 2015年12月30日 08:26:36
  • 转载请务必保留本文链接:https://go.coder-hub.com/34521255.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定