指针(Go语言)

huangapple go评论65阅读模式
英文:

Pointers (GoLang)

问题

这是一个初学者的问题,请耐心等待。疑问是为什么f()函数指向不同的地址。我的理解是变量v必须覆盖旧值。

package main
import "fmt"

var p = f()

func f() *int {
    v := 1
    return &v
}

func main() {
    fmt.Println(f())
    fmt.Println(f())
    fmt.Println(f())
    fmt.Println(p)
}

//0xc0000140b0
//0xc0000140b8
//0xc0000140e0
//0xc000014098

这段代码中,函数f()每次被调用时,都会创建一个新的局部变量v,并返回其地址。因此,每次调用f()时,返回的地址都是不同的。变量p在全局作用域中调用f(),因此它只会在程序启动时被初始化一次,所以它的值是固定的。

英文:

This is a rookie question, please bear with me. So the doubt is why f() function points different address. My understanding is the variable v must overwrite the old value.

package main
import "fmt"

var p = f()

func f() *int {
    v := 1
    return &v
}

func main() {
	fmt.Println(f())
	fmt.Println(f())
	fmt.Println(f())
	fmt.Println(p)
}

//0xc0000140b0
//0xc0000140b8
//0xc0000140e0
//0xc000014098

答案1

得分: 5

编译器检测到v在函数f逃逸,所以它在堆上分配。每次调用f都会返回v的一个新实例,这就是为什么每次调用都会看到不同的地址。

英文:

The compiler detects that v escapes the function f, so it is allocated on the heap. Each call to f returns a new instance of v, that's why you see a different address for each call.

答案2

得分: 1

简单回答一下:

> Go语言会寻找超出当前栈帧的变量,并将它们分配到堆上。

基本上,变量v逃逸了函数f的栈帧,并在堆上分配内存,这就是为什么每次打印时看到不同的地址。

阅读这篇关于逃逸分析的好文章:https://medium.com/a-journey-with-go/go-introduction-to-the-escape-analysis-f7610174e890

尝试运行逃逸分析,查看所有逃逸的变量。

go build -gcflags="-m" main.go:
./main.go:7:2: moved to heap: v   //指向v := 1
./main.go:12:15: moved to heap: v //指向fmt.Println(f())
./main.go:13:15: moved to heap: v //指向fmt.Println(f())
./main.go:14:15: moved to heap: v //指向fmt.Println(f())

请注意,最后一个fmt.Println(f())语句不被认为是逃逸的,因为传递给Println的值是全局变量p,它已经在堆上,因此不需要逃逸。

英文:

To give a simple answer to this

> Go looks for variables that outlive the current stack frame and
> then heap-allocates them

Basically, the variable v escapes the function f stack frame and gets allocated in heap which is why you see different addresses printed everytime.

Read this nice introduction to escape analysis. https://medium.com/a-journey-with-go/go-introduction-to-the-escape-analysis-f7610174e890

Try running escape analysis to see all the variables that got escaped.

go build -gcflags="-m" main.go:
./main.go:7:2: moved to heap: v   //points to v := 1
./main.go:12:15: moved to heap: v //points to fmt.Println(f())
./main.go:13:15: moved to heap: v //points to fmt.Println(f())
./main.go:14:15: moved to heap: v //points to fmt.Println(f())

Note that the last fmt.Println(f()) statement is not considered for escaping as value passed to Println is p which is a global variable so its already in heap and thus doesn't need to escape.

huangapple
  • 本文由 发表于 2021年11月2日 00:50:37
  • 转载请务必保留本文链接:https://go.coder-hub.com/69800088.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定