
go 中的 `const` 声明具有词法作用域,同名常量在不同作用域中互不干扰;函数内重新声明的 `const` 会遮蔽外层同名常量,而非覆盖或修改它。
在 Go 语言中,“常量不可变”这一原则始终成立——但关键在于:不可变 ≠ 不可遮蔽。所谓“重声明”(如在 main 函数中再次写 const s = 0)并非修改已存在的常量,而是定义一个新常量,其作用域仅限于当前代码块(如函数体、花括号内的子作用域)。外层声明的 const s string = "constant" 依然存在且未被触碰,只是在 main 函数内部被同名的新常量暂时“遮蔽”(shadowing)了。
这种行为与 Go 中变量(var)的遮蔽规则一致,是语言设计上对作用域清晰性和局部性的重要支持。下面是一个更直观的演示:
package main
import "fmt"
const s string = "global constant" // 包级常量
func main() {
const s = 0 // 函数级常量:类型为 int,遮蔽外层 s
fmt.Println(s) // 输出: 0
{
const s = 3.14 // 局部块级常量:float64 类型
fmt.Println(s) // 输出: 3.14
}
fmt.Println(s) // 仍输出: 0(回到 main 作用域,非 global)
}✅ 关键要点总结:
- 每个 const 声明都绑定到其最近的词法作用域(包、函数、甚至 {} 内部);
- 同名常量在内层作用域中会自动遮蔽外层同名标识符,编译器不会报错;
- 遮蔽不影响外层常量的值、类型或生命周期,它们仍可被其他未遮蔽作用域访问;
- 若需引用外层常量,可通过显式作用域限定(如包名前缀)——但包级常量默认可导出访问,而函数内常量无法从外部访问。
⚠️ 注意事项:
- 过度使用遮蔽可能降低代码可读性,尤其当同名常量类型或含义差异较大时(如 s 既是字符串又是整数);
- Go 编译器不会警告遮蔽行为,因此建议在团队规范中约定命名习惯,避免无意义的重名;
- const 遮蔽仅适用于编译期确定的常量,与 var 的运行时变量遮蔽机制原理相同,但语义更严格(因常量无内存地址、不可寻址)。
理解作用域与遮蔽,是写出清晰、可维护 Go 代码的基础——它让局部逻辑得以封装,同时保障全局常量的稳定性与安全性。










