英文:
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
.
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论