【问题标题】:Why struct I pass does not change为什么我通过的结构没有改变
【发布时间】:2016-04-02 07:21:36
【问题描述】:

我通过引用将结构传递给函数。

我期待如果我在函数内部定义和更改结构,我可以在外部获取新值。

但这并没有发生。

谁能解释一下原因?

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

【问题讨论】:

  • 请考虑忘记这个“通过引用”的误称。在某些语言中,有的区别:例如,在 Python 和 PHP 中,整数类型的值通过值传递,而类类型的对象通过引用传递。相反,在 Go 中,所有值都是按值传递的,只是您可以显式传递指向值的指针——如果您希望被调用者修改指向的值,或者想要避免复制开销。
  • 考虑阅读thisthis

标签: function pointers go


【解决方案1】:

您并没有更改函数内部的结构,而是通过将其设置为不同的内存地址来更改值。换句话说,你没有改变存储在t引用的地址的对象,你改变了t本身的指针值,这不会改变函数外t变量的指针值(因为 Golang 是传值的)。

为了做你想做的事,代码应该看起来类似于你为intbyRef做的事情,即:

func change(t *ttt) {
    var p ttt = ttt{7}
    fmt.Println(p)
    *t = p
}

但是,这会因 nil 指针取消引用而恐慌。您的 main 函数也应该执行您对 int 所做的操作:

func main() {

    i := 1
    // var t *ttt
    t := new(ttt)

    ...
}

完整代码如下(游乐场链接here):

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)
}

此外,您可能希望防止出现 nil 值和返回错误,尤其是对于包内部的函数。

【讨论】:

  • 关于«一般来说,您应该防范 nil 值和返回错误。» ——请不要! Here's为什么。
【解决方案2】:

在我们的代码中,您在函数更改中创建 ttt 的新对象并将其分配给作为参数传递给函数的 t。在 go 中,参数是按值传递的,因此在函数更改结束时,您将值分配给 t 仅适用于函数的范围。为了将更改传播到从更改中调用函数返回值并将其分配回去。

已对您的代码进行了更改,请查看 Playground 链接 https://play.golang.org/p/S3GK0JLDHn

【讨论】:

    【解决方案3】:

    您将 initialized 指针值传递给 intByRef 并更改取消引用的值。

    change 中,您传递未初始化的指针值(又名 nil)并为其分配另一个指针。

    所以你在做两件不同的事情。

    您应该知道,当您将指针传递给函数时,您会传递该指针的副本(指向相同的值)。这就是为什么maint 在将它传递给change 之后没有改变。它指向“旧”内存地址。

    如果您想更改传递给函数的ttt 指针的值,您可以像在intByRef 中那样做,但是指针必须 被初始化(也就是分配) .否则你会尝试取消引用 nil。

    playground

    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)
    }
    

    【讨论】:

      猜你喜欢
      • 2021-10-31
      • 2018-11-21
      • 2016-01-03
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2018-01-25
      相关资源
      最近更新 更多