为了账号安全,请及时绑定邮箱和手机立即绑定

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

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

Go
繁星coding 2023-08-07 11:09:59
我写了下面的代码。我知道返回在函数中创建的变量的地址是错误的方法,因为创建的局部变量将位于堆栈中,并且在完成函数后该变量将从堆栈中弹出。我创建了一个名为“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”。这里有什么问题吗?
查看完整描述

1 回答

?
泛舟湖上清波郎朗

TA贡献1818条经验 获得超3个赞

这被称为“逃逸分析”。


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续生活。


查看完整回答
反对 回复 2023-08-07
  • 1 回答
  • 0 关注
  • 115 浏览
慕课专栏
更多

添加回答

举报

0/150
提交
取消
意见反馈 帮助中心 APP下载
官方微信