
go 语言允许在不同作用域中声明同名常量,这并非修改原有常量,而是通过作用域隔离实现的“遮蔽(shadowing)”,外层常量保持不变,内层声明仅在自身作用域内生效。
在 Go 中,const 并非全局唯一标识符,而是遵循严格的作用域规则。当你在 main 函数内部再次声明 const s = 0,它并不会覆盖包级声明的 const s string = "constant",而是在 main 函数的作用域中创建了一个全新的、独立的常量,该常量仅在 main 函数体内可见。包级常量 s 依然存在且未被修改——只是被“遮蔽”了。
这种行为与变量(var)的遮蔽机制完全一致,是 Go 作用域设计的自然体现。以下示例清晰展示了多层作用域下的遮蔽效果:
package main
import "fmt"
const s string = "constant" // 包级常量,作用域为整个包
func main() {
const s = 0 // 函数级常量,类型自动推导为 int,遮蔽包级 s
fmt.Println(s) // 输出: 0
{
const s = 3.14 // 块级常量,类型为 float64,遮蔽函数级 s
fmt.Println(s) // 输出: 3.14
}
fmt.Println(s) // 仍输出: 0(块级 s 作用域已结束)
}⚠️ 注意事项:
- 常量遮蔽不触发编译错误,但可能降低代码可读性。建议避免无必要地重用常量名;
- 遮蔽仅发生在嵌套作用域中(如函数内、代码块 {} 内),同级作用域重复声明同名常量会报错:redeclared in this block;
- 类型可不同(如包级 string vs 函数级 int),因 Go 常量是类型化或无类型的,且各自独立推导;
- 若需访问被遮蔽的外层常量,无法通过别名直接引用(Go 不支持作用域限定符如 package.s),应改用不同名称以明确语义。
总结:Go 的常量不可变(immutable),但可被同名新常量在更内层作用域中遮蔽——这是作用域机制的体现,而非对“不可变性”的违背。理解遮蔽有助于编写清晰、无歧义的常量定义,并规避潜在的逻辑混淆。









