Skip to content

Go常量 ​

阅读提示

  • 适用版本:Go 1.21+(示例在 Go 1.22 下验证)· 前置知识:变量 · 阅读时长:约 5 分钟

常量的值无法在运行时改变,一旦赋值过后就无法修改,其值只能来源于:

  • 字面量
  • 其他常量标识符
  • 常量表达式
  • 结果是常量的类型转换
  • iota

常量只能是基本数据类型,不能是

  • 除基本类型以外的其它类型,如结构体,接口,切片,数组等
  • 函数的返回值

常量的值无法被修改,否则无法通过编译

初始化 ​

常量的声明需要用到const关键字,常量在声明时就必须初始化一个值,并且常量的类型可以省略,例如

go
const name string = "Jack" // 字面量

const msg = "hello world" // 字面量

const num = 1 // 字面量

const numExpression = (1+2+3) / 2 % 100 + num // 常量表达式

如果仅仅只是声明而不指定值,将会无法通过编译

go
const name string

编译器报错

missing init expr for name

批量声明常量可以用()括起来以提升可读性,可以存在多个()达到分组的效果。

go
const (
   Count = 1
   Name  = "Jack"
)

const (
   Size = 16
   Len  = 25
)

在同一个常量分组中,在已经赋值的常量后面的常量可以不用赋值,其值默认就是前一个的值,比如

go
const (
  A = 1
  B // 1
  C // 1
  D // 1
  E // 1
)

iota ​

iota是一个内置的常量标识符,通常用于表示一个常量声明中的无类型整数序数,一般都是在括号中使用。

go
const iota = 0

看几个使用案例

go
const (
   Num = iota // 0
   Num1 // 1
   Num2 // 2
   Num3 // 3
   Num4 // 4
)

也可以这么写

go
const (
   Num = iota*2 // 0
   Num1 // 2
   Num2 // 4
   Num3 // 6
   Num4 // 8
)

还可以

go
const (
   Num = iota << 2*3 + 1 // 1
   Num1 // 13
   Num2 // 25
   Num3 = iota // 3
   Num4 // 4
)

通过上面几个例子可以发现,iota是递增的,第一个常量使用iota值的表达式,根据序号值的变化会自动的赋值给后续的常量,直到用新的const重置,这个序号其实就是代码的相对行号,是相对于当前分组的起始行号,看下面的例子

go
const (
  Num  = iota<<2*3 + 1 // 1 第一行
  Num2 = iota<<2*3 + 1 // 13 第二行
  _ // 25 第三行
  Num3 //37 第四行
  Num4 = iota // 4 第五行
  _ // 5 第六行
  Num5 // 6 第七行
)

例子中使用了匿名标识符_占了一行的位置,可以看到iota的值本质上就是iota所在行相对于当前const分组的第一行的差值。而不同的const分组则相互不会影响。

枚举 ​

Go 语言没有为枚举单独设计一个数据类型,不像其它语言通常会有一个enum来表示。一般在 Go 中,都是通过自定义类型 + const + iota 来实现枚举,下面是一个简单的例子

go
type Season uint8

const (
  Spring Season = iota
  Summer
  Autumn
  Winter
)

这些枚举实际上就是数字,Go 也不支持直接将其转换为字符串,但我们可以通过给自定义类型添加方法来返回其字符串表现形式,实现Stringer接口即可。

go
func (s Season) String() string {
  switch s {
  case Spring:
    return "spring"
  case Summer:
    return "summer"
  case Autumn:
    return "autumn"
  case Winter:
    return "winter"
  }
  return ""
}

这样一来就是一个简单的枚举实现了。你也可以通过官方工具Stringer来自动生成枚举。

不过它有以下缺点:

  • 类型不安全,因为Season是自定义类型,可以通过强制类型转换将其他数字也转换成该类型

    go
    Season(6)
  • 繁琐,字符串表现形式需要自己实现

  • 表达能力弱,因为const仅支持基本数据类型,所以这些枚举值也只能用字符串和数字来进行表示

为什么不在语言层面支持枚举是笔者非常不能理解的一件事,我认为这绝对是利大于弊的。

完整示例 ​

下面的程序可以直接运行:复制到文件后执行 go run main.go,或粘贴到 Go Playground 运行。

go
package main

import "fmt"

// iota:const 块中第一个常量为 0,之后每个 ConstSpec 递增 1
const (
	KB = 1 << (10 * (iota + 1))
	MB
	GB
)

// 带类型的枚举风格常量
type Weekday int

const (
	Sunday Weekday = iota
	Monday
	Tuesday
)

func main() {
	fmt.Println(KB, MB, GB)
	fmt.Println(Sunday, Monday, Tuesday)

	const pi = 3.14159
	const greeting = "hello"
	fmt.Println(pi, greeting)
}

预期输出:

text
1024 1048576 1073741824
0 1 2
3.14159 hello

常见错误与踩坑 ​

  • 常量不能被赋值,也不能取地址。 const c = 1; c = 2 与 &c 都无法编译。
  • iota 只在当前 const 块内有效,每个块都从 0 重新开始,且每个 ConstSpec 递增;可以用 _ = iota 跳过值。
  • 位移与 iota 组合时注意加括号。 1 << 10 * (iota + 1) 实际按 (1 << 10) * (iota + 1) 结合,与直觉不符。
  • 只有基本类型能作为常量。 切片、映射、结构体、数组都不能用 const,应使用包级 var。
  • 无类型常量会随上下文推断类型。 const x = 1 可用于 int 或 float64;一旦显式指定类型,转换就需要显式书写。

更新记录 ​

  • 2026-10-14:新增"阅读提示"、完整可运行示例(含预期输出)、常见错误与踩坑清单,以及本更新记录。