指针(GoLang)

Posted

技术标签:

【中文标题】指针(GoLang)【英文标题】:Pointers (GoLang) 【发布时间】:2021-12-16 08:54:17 【问题描述】:

这是一个菜鸟问题,请多多包涵。所以问题是为什么 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

【问题讨论】:

"我的理解是变量 v 必须覆盖旧值。"语言规范(值得一读!)在这种情况下不做任何保证。不保证地址保持不变,也不能保证必须更改。甚至不同的编译器也可能做不同的事情。 与答案无关,但我对正确的英语表达 bear with me 表示赞赏。如此多的人(尤其是美国人)写“bare with me”,这具有相当……不同的含义。 :-) 同时,另一个小的英语点:你写“怀疑”的地方,你的意思是“问题”。这些之间有一个微妙的区别:doubt 具有怀疑的含义,而 question 没有:doubt 具有暗示的“可能甚至可能false”内置在其中。 【参考方案1】:

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

【讨论】:

这确实是 OP 看到他现在看到的结果的原因。然而,由于v 的每个实例在下一次调用时都已“死”,因此语言规范允许编译器重新使用旧地址。这个编译器根本不够聪明。 如果 GC 在两次调用之间运行,它就有机会释放变量。在这种情况下,它没有机会运行。 @torek,编译器真的会这样做吗,不知道是否还有其他对该函数的调用? 一个无所不知(或至少足够聪明)的编译器会知道 fmt.Println 不允许保存指针,因此当值从 f 转义到 main 时,它确实不会从 那里 逃逸,因此分配本身可以向上移动到 main 本身的堆栈帧。如果f 被内联并且fmt.Println 被特例化为“纯”,那么简单的逃逸分析就足够了,我们根本不需要运行GC。 (注意:我在这里误用了pure的通常编译器特定的含义:纯函数是没有副作用的,输出是一种副作用,所以打印是本质上是不纯的。但我认为意思很清楚。)在编译时让编译器分析 fmt.Println 是“纯”的,因为它调用的所有内容同样是“纯”的,通常是有用的,然后会启用这种类型优化。【参考方案2】:

给出一个简单的答案

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   //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())

请注意,最后一个 fmt.Println(f()) 语句不考虑转义,因为传递给 Println 的值是 p,它是一个全局变量,因此它已经在堆中,因此不需要 escape

【讨论】:

谢谢@anuraag_100 作为一个小人物这对我帮助很大

以上是关于指针(GoLang)的主要内容,如果未能解决你的问题,请参考以下文章

golang之不安全编程

Golang入门到项目实战 | golang指针

Golang入门到项目实战 | golang结构体指针

Golang入门到项目实战 | golang结构体指针

golang Golang Snippet - 使用不安全指针进行切片变异

Golang✔️走进 Go 语言✔️ 第十一课 指针