go的const是编译期字面量,无内存地址,不可取址;仅支持基础类型;无类型常量依上下文推导类型,影响接口赋值与泛型匹配;编译器激进优化,但大字符串仍占二进制只读段。

const 值在编译期就固定,不能取地址
Go 的 const 不是运行时变量,而是编译器直接替换的字面量。它没有内存地址,所以 &x 会报错 cannot take the address of x。
常见错误现象:想把 const 当作指针传参、放进切片或 map 的地址位置、或者用 unsafe.Pointer 转换——全都不行。
-
const port = 8080→ 可以直接用于http.ListenAndServe(":8080", nil),但http.ListenAndServe(fmt.Sprintf(":%d", port), nil)会多一次运行时计算(虽小但存在) - 如果需要地址(比如测试中传指针),必须先赋值给变量:
var p = port,再用&p - 字符串
const是“无类型字面量”,可隐式转为string、fmt.Stringer等,但无法调用方法(没接收者)
const 类型推导规则影响接口赋值
未显式指定类型的 const(如 const x = 42)是“无类型常量”,在赋值或传参时按上下文推导类型;一旦指定类型(const x int = 42),就严格按该类型处理。
这直接影响能否赋给接口类型:
立即学习“go语言免费学习笔记(深入)”;
-
const s = "hello"→ 可赋给io.Writer?不行,因为s是无类型字符串,而io.Writer需要具体类型实现(如*bytes.Buffer) -
const s string = "hello"→ 仍是string类型,依然不能直接赋给io.Writer(string没实现该接口) - 真正能进接口的是变量:比如
var b bytes.Buffer; fmt.Fprint(&b, s)—— 这里&b才是io.Writer
const 不能用于 slice/map/channel/func 等复合类型
Go 规定 const 只能是基础字面量类型:布尔、数字、字符串、以及它们的别名。任何含运行时结构的类型都不允许。
典型误用场景:
-
const arr = []int{1,2,3}→ 编译错误:invalid array literal in const declaration -
const m = map[string]int{"a": 1}→ 同样报错,map必须用make或字面量在运行时构造 -
const fn = func() {}→ 不合法,函数值是运行时对象,且类型含闭包信息,无法编译期确定 - 替代方案:用
var+init()或包级变量初始化,或封装为返回值的函数(如func DefaultConfig() Config { ... })
const 在性能和二进制体积上的实际影响
编译器对 const 的优化很激进:只要不被反射或 unsafe 绕过,所有使用点都会内联为立即数,不占数据段空间,也不产生读内存指令。
但要注意边界情况:
- 大字符串
const html = `...50KB HTML...`→ 编译后仍会存入二进制只读段,不是“完全消失”;若仅需部分片段,建议拆成小const或用embed.FS - 浮点
const pi = 3.14159265359→ Go 默认用float64,但若上下文是float32(如math.Sin(float32(pi))),会先转float64再截断,可能引入微小误差 - 跨包引用
const(如pkg.AConst)→ 导入方编译时直接拷贝值,不依赖运行时链接,这也是 Go 常量“零成本抽象”的核心
最易被忽略的一点:const 的类型精度会影响泛型约束匹配。比如 type Number interface{ ~int | ~int64 },那么 const x = 42 可以传入,但 const x int32 = 42 就不行——类型必须落在约束范围内,而不是靠推导“大概像”。










