Go 中 const 值没有内存地址,因其在编译期被直接替换为字面值,不分配运行时内存,故无法取地址,任何 &constValue 都会触发编译错误;需用 var 声明变量后取址。

Go 中 const 值没有内存地址
因为 const 在编译期就被替换成字面值,不分配运行时内存。Go 编译器会把所有对常量的引用直接内联为对应值(比如 const pi = 3.14159,后续写 &pi 时,编译器根本找不到一个“变量”来取地址)。
这和 C/C++ 不同:C 的 const 变量仍占内存(只是加了只读修饰),而 Go 的 const 是纯编译期符号,连符号表里都不一定保留。
&constValue 会直接报错 cannot take the address of ...
尝试对任何 const 取地址都会触发编译错误,无论类型是 int、string 还是自定义类型:
const name = "gopher" ptr := &name // 编译错误:cannot take the address of name
常见误操作场景:
立即学习“go语言免费学习笔记(深入)”;
- 想传指针给函数(比如
fmt.Printf("%s", &name))→ 改用&temp(先赋值给变量) - 初始化结构体字段为指针(
Config{Title: &name})→ 必须先声明变量:title := name; Config{Title: &title} - 在切片或 map 中存常量地址 → 不可行,需用变量兜底
替代方案:用变量包装常量再取地址
如果确实需要指针,唯一合法方式是用 var 显式声明变量,并初始化为该常量:
const mode = 0644 var modeVar = mode permPtr := &modeVar // ✅ 合法
注意点:
- 不能写成
var modeVar = constValue然后立即取地址——必须分两步或确保变量已分配空间 - 短变量声明
:=也有效:modeVar := mode; ptr := &modeVar - 这种变量不会被编译器优化掉,哪怕值和常量完全一样
为什么设计成这样?性能与语义一致性
Go 把常量视为“值本身”,不是“可寻址实体”。这种设计带来两个实际好处:
- 避免对字面值取地址引发的歧义(比如
&42或&"hello"在其他语言中行为不一) - 让编译器能更激进地做常量折叠和内联,减少不必要的内存分配
- 强制开发者区分“不可变值”(
const)和“只读存储位置”(var + const初始化)
真正容易被忽略的是:哪怕常量类型实现了接口,也不能直接取地址转为接口指针——必须经过变量中转。这点在写泛型约束或反射逻辑时特别容易踩坑。










