讲解

常量用 const 声明,值在编译期就确定,之后不能修改。语法和 var 几乎一样,但可以省略类型让编译器推断:const Pi = 3.14。常量只能是基本类型(数字、字符串、布尔),不能是切片、map 这类复合值,因为它们的值要在运行期构造。

Go 常量有一个独特设计:不写类型的常量是「无类型常量」,它不带固定类型,会根据上下文自动适配。const Big = 1 << 40 既可以直接赋给 int64,也可以参与浮点运算。这种灵活性让常量在表达式里非常顺手,直到显式赋给某个具体类型的变量时才「定型」。

iota 是常量声明里的行计数器,从 0 开始逐行递增,专门用来优雅地定义枚举。配合自定义类型(type Weekday int),就能写出既有可读性又有类型安全的星期、状态码、权限位等枚举。常见的另一个用法是 1 << (10 * iota) 生成 KB、MB、GB 这样的字节单位序列。

示例

基本常量与无类型常量的灵活性:

package main

import "fmt"

const Pi = 3.14159
const SiteName = "ohmydocs"

func main() {
	const DaysInWeek = 7
	fmt.Println(Pi, SiteName, DaysInWeek)

	// 无类型常量自动适配上下文
	const Big = 1 << 40
	var i64 int64 = Big
	var f float64 = Big
	fmt.Println("同一个常量两种用途:", i64, f)
}

用 iota 定义星期枚举和字节单位:

package main

import "fmt"

type Weekday int

const (
	Sunday Weekday = iota
	Monday
	Tuesday
	Wednesday
	Thursday
	Friday
	Saturday
)

func main() {
	fmt.Println("Monday =", Monday, ", Friday =", Friday)

	const (
		_  = 1 << (10 * iota) // 跳过 0 那一行
		KB                    // 1024
		MB                    // 1048576
		GB
	)
	fmt.Println("1KB =", KB, "字节, 1MB =", MB, "字节, 1GB =", GB, "字节")
}

常见坑

  • 试图给常量赋运行期的值:const now = time.Now() 编译不过,常量的值必须编译期可计算。运行期才确定的值请用变量。
  • 枚举从 0 开始埋雷:iota 默认从 0 开始,而 0 恰好是类型的零值——未初始化的 Weekday 变量会「自动等于 Sunday」。常用技巧是第一个枚举值用 _ 丢弃,让有效值从 1 开始。
  • 以为不同 const 块共享 iota:iota 在每个 const 块内从 0 重新开始。两个块里的第一个值都是 0,互不影响。
  • 在 iota 序列中间改写法:iota 序列靠「重复上一行表达式」工作,中间某一行写了不同的表达式,后续行就跟随新的表达式。保持序列写法一致,断了就显式写出每一行。

小结

const 定义编译期常量,无类型常量自动适配上下文,iota 是定义枚举和递增序列的官方姿势。下一节深入学习字符串与 rune——Go 处理中文的关键。