为什么我传递的结构体没有改变?

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

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&#39;re not changing the object stored at the address referenced by `t`, you&#39;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&#39;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&#39;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 &quot;fmt&quot;
    
    func intbyRef(i *int) {
        *i = 10
    }
    
    type ttt struct {
        a int
    }
    
    func change(t *ttt) {
        var p ttt = ttt{7}
        fmt.Println(p)
        // t = &amp;p
        *t = p
    
    }
    
    func main() {
    
        i := 1
        // var t *ttt
        t := new(ttt)
    
        fmt.Println(i)
        fmt.Println(t)
    
        change(t)
        intbyRef(&amp;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&#39;s why `main`&#39;s `t` is unchanged after passing it to `change`. It points to the &quot;old&quot; 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&#39;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>



huangapple
  • 本文由 发表于 2015年12月28日 19:20:29
  • 转载请务必保留本文链接:https://go.coder-hub.com/34493586.html
匿名

发表评论

匿名网友

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

确定