Go 中的 const 声明支持作用域内重名(即变量遮蔽),而非重新赋值或修改

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 代码的基础——它让局部逻辑得以封装,同时保障全局常量的稳定性与安全性。