Go的const是编译期确定、不可修改、不分配地址的绑定,必须带初始值,支持iota但仅限单块且易被显式值打断,仅允许字面量,类型推导需谨慎。

Go 语言的 const 不是“定义常量”,而是声明一个编译期确定、不可修改、不分配地址的绑定;没给初始值就报错,类型推导有隐式规则,iota 每块重置且极易被显式赋值打断。
const 必须带初始值,不能空声明
Go 不允许 const port 这种写法,编译器直接报 missing value in const declaration。哪怕你打算后续再赋值,也不行——这和 var 完全不同。
-
const port = 8080✅ 类型由字面量推导为int -
const timeout time.Duration = 30 * time.Second✅ 显式类型更安全,避免跨包传参时类型不匹配 -
const version❌ 缺少=和右值,语法错误
常见误用是照搬其他语言习惯,在配置文件读取后想用 const dbHost = os.Getenv("DB_HOST") ——这会触发 function call not allowed in constant expression,必须改用 var 或 init()。
iota 只在单个 const 块内有效,混用显式值会中断计数
iota 不是全局计数器,它只在当前 const ( ... ) 块里从 0 开始,每行加 1。一旦某行用了显式值(比如字符串或数字),后续未显式赋值的常量会继承该类型,且 iota 不再推进。
立即学习“go语言免费学习笔记(深入)”;
-
const ( A = iota; B; C )→A=0, B=1, C=2,全是int -
const ( X = iota; Y; Z = "http"; W )→X=0, Y=1, Z="http", W="http"(不是 2!) - 想跳过某值又不打断序列?用
_ = iota占位
跨多个 const 块写枚举时,别指望 iota 连续:每个块都从 0 重新开始。
const 只支持编译期字面量,不能是 slice/map/function
Go 的 const 仅接受布尔、数字、字符串及其底层类型别名。任何需要运行时构造或堆分配的类型都不合法。
-
const names = []string{"a", "b"}❌ slice 字面量不允许 -
const cfg = map[string]int{"x": 1}❌ map 不可作常量 -
const maxRetries = 3✅ 整数字面量 -
const version = "v1.2.0"✅ 字符串字面量
连类型别名也受限:若 type ID []int,则 const id ID = []int{1} 依然非法。真正容易被忽略的是——混合使用整数和浮点数字面量时,Go 会尝试隐式转换,但失败时错误信息极简,往往只报 cannot use ... as ... in assignment,得逐行核对类型推导是否一致。
无类型常量 vs 显式类型:影响赋值和 API 兼容性
像 const timeout = 5000 这种写法产生的是“无类型整数常量”,它在参与运算时可灵活转换,但也埋下隐患:
-
var d time.Duration = timeout * time.Millisecond✅ OK -
var x int32 = timeout❌ 编译失败:不能把无类型 int 赋给int32
对接外部库、Cgo 或结构体字段时,类型必须精确匹配。推荐显式声明:const timeout int32 = 5000、const enabled bool = true。字符串常量加 string 类型还能防止被误当作 []byte 处理。
最常被忽略的一点:const 块中如果某行省略了类型和值,它会悄悄继承上一行的类型——哪怕那行用的是 iota,而下一行突然写了字符串,后续所有省略行都会变成 string 类型。这种类型“漂移”很难一眼发现,调试时容易绕弯路。


















