如何在Golang中获取变量的内存地址 Go语言取地址符&应用

5次阅读

go中&用于获取可寻址变量的内存地址,结果为对应类型指针;字面量、map元素、函数返回值等不可寻址值禁止取地址,否则编译报错。

如何在Golang中获取变量的内存地址 Go语言取地址符&应用

Go 中 & 取地址符的基本用法

Go 的 & 操作符用于获取变量的内存地址,结果类型是对应类型的指针(如 *int)。它只能作用于「可寻址」的值——也就是有固定内存位置的变量,不能对字面量、函数调用返回值、map 元素(除非先赋给局部变量)、channel 接收表达式等直接取地址。

  • &x 合法:当 x 是声明过的变量(var x intx := 42
  • &42 非法:字面量不可寻址,编译报错 cannot take the address of 42
  • &m["key"] 非法:map 元素在 Go 中不保证可寻址,编译报错 cannot take the address of m["key"]
  • &s[0] 合法:切片、数组元素可寻址(只要 s 本身可寻址)

为什么 & 有时编译失败?常见不可寻址场景

Go 编译器对“可寻址性”检查很严格,不是所有看起来像变量的东西都能取地址。核心原则是:该值必须有稳定、可预测的内存位置,且生命周期可控。

  • 函数返回值(即使返回的是局部变量副本):&fmt.Sprintf("x") ❌ 报错 cannot take the address of fmt.Sprintf("x")
  • Struct 字段访问链中含不可寻址中间项:&(s.f).g 如果 s.f 是值拷贝(比如 f 是非指针字段),则整个表达式不可寻址
  • Interface{} 类型变量的底层值:var i interface{} = 42; &i 得到的是 *interface{},不是 *int;想取底层值地址,必须先断言并赋给变量:if v, ok := i.(int); ok { p := &v }
  • range 循环中的迭代变量:for _, v := range s { &v } 总是取到同一个地址(因为 v 是每次迭代复用的变量),这不是 bug,但常被误用

取地址后传参:指针传递与逃逸分析的关系

&x 把变量地址传给函数,看似只是语法动作,但会影响编译器的逃逸分析结果——这直接决定变量分配在还是上。

  • 如果函数参数是 *T 且该指针被“逃逸”(比如存入全局变量、返回、传给 goroutine),那么 x 会被强制分配到堆,即使它原本很小、生命周期短
  • 避免无谓取地址:例如 fmt.Printf("%p", &x) 不会逃逸;但 store(&x)store 声明为 func store(p *int) { globalPtr = p },就会导致 x 逃逸
  • 验证方式:加 -gcflags="-m" 编译,看输出是否含 ... escapes to heap

struct 字段取地址的边界情况

对 struct 字段取地址时,不仅要看字段本身类型,还要看 struct 实例是否可寻址。

立即学习go语言免费学习笔记(深入)”;

  • type S struct{ x int }; var s S; &s.x ✅ 安全
  • func get() S { return S{1} }; &get().x ❌ 编译失败:临时 struct 值不可寻址
  • type T struct{ y *int }; t := T{&x}; &t.y ✅ 得到 **int,但注意这是指针的地址,不是 *int 指向的值的地址
  • 嵌入字段同理:type E struct{ S }; e := E{}; &e.x ✅ 等价于 &e.S.x,前提是 e 可寻址

最易忽略的一点:取地址操作本身不改变原值,但拿到指针后任何解引用写操作都会影响原变量——这点在并发闭包捕获中尤其容易出问题。

text=ZqhQzanResources