【问题标题】:Returning Address of Local Variable Generates Unexpected Value局部变量的返回地址产生意外的值
【发布时间】:2019-11-20 19:30:35
【问题描述】:

我写了下面的代码。我知道返回一个变量的地址 在函数中创建是错误的方法,因为创建的局部变量将在堆栈中,并且 完成函数后,变量将从堆栈中弹出。 我创建了一个名为“latif”的人。然后我使用了 changeName() 函数。它将人员结构的名称字段更改为“uluman”。它返回了局部变量的地址。完成函数后,应该弹出局部变量。然后我调用 sum() 函数来保证堆栈会改变(sum 函数的参数将被推送。换句话说,内存中的单元格值 x 点应该改变)。所以 x 指向堆栈中的某个位置。

package main
    import "fmt"

    type Person struct{
        name string
        age int

    }
    func sum(a, b int)int{
       return a+b
    }
    func (t Person ) changeName(value string)*Person{
        t.name = value
        return &t  //Delibiratly the address of the local variable is returned
    }
    func main(){
        t := Person{name : "latif" }

        fmt.Println("Before" , t.name)
        x := t.changeName("uluman")
        _= sum(5,10)
        fmt.Println("After" , x.name)



        return
    }

我预计 fmt.Println(x.name) 应该打印与 'uluman' 不同的东西,因为 x 点堆栈地址已经改变,但是它打印了'uluman'。 这里有什么问题?

【问题讨论】:

标签: pointers go stack


【解决方案1】:

这叫“逃逸分析”。

Go 编译器试图找出一个变量的地址是否“转义”了一个函数,如果是,它会在堆而不是堆栈中分配变量。在这种情况下,它发现t的地址转义了changeName函数,所以它分配在堆中,而不是在堆栈中。这就是您的程序有效的原因。

例如,这是构造结构的常用方法:

type X struct {
  ...
}

func NewX() *X {
   a:=X{}
   ...
   return &a
}

这里,a 分配在堆中,而不是在堆栈中,因为编译器知道 a 会转义函数。

以下也是有效的:

func f() {
  i:=0
  go func() {
    ...
    i++
    ...
   }()
}

上面,i 转义了f,因为i 的地址在新创建的goroutine 的闭包中。 f 回归后,i 继续存在。

【讨论】:

    猜你喜欢
    • 2021-04-28
    • 1970-01-01
    • 1970-01-01
    • 2014-05-14
    • 2012-09-07
    • 2012-09-05
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多