局部变量的返回地址生成意外值

我写了下面的代码。我知道返回在函数中创建的变量的地址是错误的方法,因为创建的局部变量将位于堆栈中,并且在完成函数后该变量将从堆栈中弹出。我创建了一个名为“latif”的人。然后我使用了changeName()函数。它将 person 结构的名称字段更改为“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”。这里有什么问题吗?


繁星coding
浏览 81回答 1
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续生活。
打开App,查看更多内容
随时随地看视频慕课网APP