英文:
Why struct I pass does not change
问题
我正在将一个结构体通过引用传递给一个函数。
我原本期望在函数内部定义和修改结构体后,可以在外部获取到新的值。
但实际上并没有发生这种情况。
有人可以解释一下为什么吗?
package main
import "fmt"
func intbyRef(i *int) {
*i = 10
}
type ttt struct {
a int
}
func change(t *ttt) {
var p ttt = ttt{7}
fmt.Println(p)
t = &p
}
func main() {
i := 1
var t *ttt
fmt.Println(i)
fmt.Println(t)
change(t)
intbyRef(&i)
fmt.Println(i)
fmt.Println(t)
}
你可以在这里尝试这段代码:https://play.golang.org/p/I-GIdIZ9c6
英文:
I am passing a struct to a function by reference.
I was expecting if I define and change the struct inside the function I can get the new value outside.
But it is not happening.
Can anyone explain why?
package main
import "fmt"
func intbyRef(i *int) {
*i = 10
}
type ttt struct {
a int
}
func change(t *ttt) {
var p ttt = ttt{7}
fmt.Println(p)
t = &p
}
func main() {
i := 1
var t *ttt
fmt.Println(i)
fmt.Println(t)
change(t)
intbyRef(&i)
fmt.Println(i)
fmt.Println(t)
}
You can try the code in here: https://play.golang.org/p/I-GIdIZ9c6
答案1
得分: 2
你没有在函数内部改变结构体本身,而是通过将其设置为不同的内存地址来改变值。换句话说,你没有改变存储在t
引用的地址上的对象,而是改变了t
本身的指针值,这不会改变函数外部的t
变量的指针值(因为Golang是按值传递)。
为了实现你想要的效果,代码应该类似于你对intbyRef
所做的操作,即:
func change(t *ttt) {
var p ttt = ttt{7}
fmt.Println(p)
*t = p
}
然而,这样做会导致空指针解引用的恐慌。你的main
函数也应该像对待int
一样处理:
func main() {
i := 1
// var t *ttt
t := new(ttt)
...
}
完整代码如下(playground链接在这里):
package main
import "fmt"
func intbyRef(i *int) {
*i = 10
}
type ttt struct {
a int
}
func change(t *ttt) {
var p ttt = ttt{7}
fmt.Println(p)
// t = &p
*t = p
}
func main() {
i := 1
// var t *ttt
t := new(ttt)
fmt.Println(i)
fmt.Println(t)
change(t)
intbyRef(&i)
fmt.Println(i)
fmt.Println(t)
}
另外,你可能希望对空值进行保护并返回错误,特别是对于你包内部的函数。
<details>
<summary>英文:</summary>
You are not changing the struct inside the function, you are changing the value by setting it to a different memory address. In other words, you're not changing the object stored at the address referenced by `t`, you're changing the pointer value of `t` itself, which will not change the pointer value of the `t` variable outside the function (because Golang is pass by value).
In order to do what you want, the code should look similar to what you're doing for `intbyRef`, namely:
func change(t *ttt) {
var p ttt = ttt{7}
fmt.Println(p)
*t = p
}
however, this will panic with a nil-pointer dereference. Your main function should also do what you're doing with the int:
func main() {
i := 1
// var t *ttt
t := new(ttt)
...
}
Full code below (playground link [here](https://play.golang.org/p/_e1cCuMmmp)):
package main
import "fmt"
func intbyRef(i *int) {
*i = 10
}
type ttt struct {
a int
}
func change(t *ttt) {
var p ttt = ttt{7}
fmt.Println(p)
// t = &p
*t = p
}
func main() {
i := 1
// var t *ttt
t := new(ttt)
fmt.Println(i)
fmt.Println(t)
change(t)
intbyRef(&i)
fmt.Println(i)
fmt.Println(t)
}
Also, you may want to be guarding against nil values and returning errors, especially for functions internal to your package.
</details>
# 答案2
**得分**: 0
在我们的代码中,你在函数change中创建了ttt的新对象,并将其赋值给作为参数传递给函数的t。在Go语言中,参数是按值传递的,所以当在函数change的末尾为t赋值时,只在函数的作用域内有效。为了将更改传播到调用函数,需要从change函数返回值,并将其重新赋值。
我已经对你的代码进行了更改,请检查playground链接:
https://play.golang.org/p/S3GK0JLDHn
<details>
<summary>英文:</summary>
In our code, you are creating new object of ttt in function change and assigning it to t which is passed as parameter to function. In go parameters are passed by value, so when at the end of function change you assign value to t is only for the scope of the function. In order to propagate change to calling function return value from change and assign it back.
Have made the changes to your code, please check play ground link
https://play.golang.org/p/S3GK0JLDHn
</details>
# 答案3
**得分**: 0
你正在将**初始化**的指针值传递给`intByRef`并更改解引用的值。
在`change`函数中,你传递的是未初始化的指针值(即nil),并将另一个指针赋值给它。
所以你在做两件不同的事情。
你应该知道,当你将指针传递给函数时,你传递的是该指针的副本(指向相同的值)。这就是为什么在将其传递给`change`函数后,`main`函数中的`t`值没有改变。它仍然指向“旧”的内存地址。
如果你想要在函数中更改传递给`ttt`指针的值,你可以像在`intByRef`函数中那样做,但是该指针**必须**被初始化(即分配内存)。否则,你将尝试对nil进行解引用操作。
[playground][1]
func change(t *ttt) {
var p ttt = ttt{7}
fmt.Println(p)
*t = p
}
func main() {
t := new(ttt)
fmt.Println(t)
change(t)
fmt.Println(t)
}
[1]: https://play.golang.org/p/ho08shnGpv
<details>
<summary>英文:</summary>
You are passing **initialized** pointer value to `intByRef` and change the dereferenced value.
In the `change` you are passing not initialized pointer value (aka nil) and assigning another pointer to it.
So you are doing two different things.
You should know that when you pass a pointer to a function you pass a copy of that pointer (pointing to the same value). That's why `main`'s `t` is unchanged after passing it to `change`. It points to the "old" memory address.
If you want to change a value of `ttt` pointer passed to the function you can do it like you do it in `intByRef`, but the pointer **must** be initialized (aka. allocated). Otherwise you'd try to dereference nil.
[playground][1]
func change(t *ttt) {
var p ttt = ttt{7}
fmt.Println(p)
*t = p
}
func main() {
t := new(ttt)
fmt.Println(t)
change(t)
fmt.Println(t)
}
[1]: https://play.golang.org/p/ho08shnGpv
</details>
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论