Go 常量与 iota 枚举
常量(constant)是一种"在程序运行期间不能改变的值"。它和变量的最大区别是:变量用 var 声明且可以反复修改,常量用 const 声明且一经定义就不可重新赋值。常量常用于圆周率、配置项、错误码、枚举值等不希望被误改的场景。
一、const 声明常量
声明常量和声明变量很像,把 var 换成 const 即可。多个相关的常量推荐用 const ( ... ) 分组放在一起,看起来更整齐。
package main
import "fmt"
// 单个常量声明
const PI = 3.14159
const Max int = 100
// 分组声明(推荐写法)
const (
Name = "Go"
Year = 2009
)
func main() {
fmt.Println(PI, Max, Name, Year)
// PI = 3 // 编译错误:不能给常量重新赋值
}注意:常量一旦定义就不能再赋值,否则编译直接报错。这个检查发生在编译期,不会拖慢运行速度。常量也必须能在编译期求值,所以你不能把函数的返回值(运行时才有结果)赋给常量。
二、iota:常量计数器
一个个手写常量的值太麻烦,Go 提供了一个特殊的常量计数器 iota。它的规则简单记住三点:
- 在每个
const块里,遇到const关键字时iota重置为 0; iota在每一行(每个常量声明)自动 +1;- 如果某一行省略了表达式,它会自动复用上一行的表达式(但
iota的值还是递增的)。
下面这个星期枚举是最经典的入门例子:
package main
import "fmt"
// iota:常量计数器,在 const 块中从 0 开始,每新增一行自动 +1
const (
Sunday = iota // 0
Monday // 1(省略表达式时,自动复用上一行)
Tuesday // 2
Wednesday // 3
Thursday // 4
Friday // 5
Saturday // 6
)
func main() {
fmt.Println(Sunday, Monday, Saturday) // 0 1 6
}周一到周六都没有写 = 某值,但它们分别得到 1~6,就是因为"复用上一行表达式 iota"再加上 iota 每行自增。这比手写 0、1、2、3…要安全得多,你随时插一行进去也不必重新排编号。
三、位标志:权限模型
iota 配合位左移 << 可以做出非常优雅的标志位(flag)。Linux 文件权限里的"可读、可写、可执行"就是这种思路:
package main
import "fmt"
// 用 iota + 位左移实现权限标志位
const (
Read = 1 << iota // 1 << 0 = 1
Write // 1 << 1 = 2
Execute // 1 << 2 = 4
)
func main() {
// 位或组合:可读 + 可写
perm := Read | Write
fmt.Println(perm) // 3
// 位与检测:是否拥有读权限
fmt.Println(perm&Read != 0) // true
}三个权限分别是 1、2、4(都是 2 的幂),用位或 | 组合起来,之后用位与 & 就能快速判断是否包含某个权限。这种"位掩码"在系统编程、配置开关、状态标记里非常常见,效率高、占用小。
四、文件大小单位
另一个高频用法是定义 KB、MB、GB 这种 1024 进制的单位。这里的小技巧是把 iota 放进表达式 10 * iota 里,让位移量随行递增,后续几行省略表达式即可自动套用:
package main
import "fmt"
// 经典用法:文件大小单位(2 的 10/20/30/40 次方)
const (
KB = 1 << (10 * iota) // 1 << 10
MB // 1 << 20
GB // 1 << 30
TB // 1 << 40
)
func main() {
fmt.Println(KB) // 1024
fmt.Println(MB) // 1048576
fmt.Println(GB) // 1073741824
}五、无类型常量
Go 的常量还有一个特别之处:无类型常量(untyped constant)。当你写 const PI = 3.14159 而不指定类型时,它并不是 float64,而是一个"数学意义上的高精度数"。它在参与运算时,会根据上下文临时确定类型,因此可以写出 var x = PI * 10(整数 10 也能直接相乘)而不报错——这若发生在变量之间是不允许的。
无类型常量默认拥有很高的精度(至少 256 位),非常适合做数学计算。一旦它被赋值给一个具体类型的变量,或用在需要明确类型的上下文里,才会"定型"。这也是 Go 对数值常量的一种贴心设计。
小结
常量用 const,不可变;iota 是 const 块里从 0 开始的行计数器,适合做枚举和位标志;省略表达式会自动复用上一行;不写类型的常量是无类型常量,精度更高、更灵活。下一篇我们来看 Go 的运算符。