我写了下面的代码。我知道返回一个变量的地址是 在函数中创建是错误的方法,因为创建的局部变量将在堆栈中,并且 完成函数后,变量将从堆栈中弹出。 我创建了一个名为“ 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”。 这里有什么问题?
答案 0 :(得分: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
继续存在。