常量(constant) 是在编译期就确定值、运行时不可更改的标识符。它们通常用于表示不会变化的数据,例如数学常数、枚举类型、位标志等。
常量中的数据类型只可以是布尔型、数字型(整数型、浮点型和复数)和字符串型。
常量的定义
Go 使用 const 关键字声明常量:
Go
const identifier [type] = value
可以省略类型说明符 [type],因为编译器可以根据变量的值来推断其类型。
- 显式类型定义:
const b string = "abc" - 隐式类型定义:
const b = "abc"
多个相同类型的声明可以简写为:
Go
const c_name1, c_name2 = value1, value2
以下实例演示了常量的应用:
Go
package main
import "fmt"
func main() {
const LENGTH int = 10
const WIDTH int = 20
var area int
//多重赋值
const a, b, c = 1, false, "str"
area = LENGTH * WIDTH
fmt.Printf("面积为:%d", area)
println()
println(a, b, c)
}
执行后输出:
面积为:200
1 false str
常量还可以用作枚举:
Go
const (
Unknown = 0
Female = 1
Male = 2
)
数字 0、1 和 2 分别代表未知性别、女性和男性。
常量可以用len(), cap(), unsafe.Sizeof()函数计算表达式的值。常量表达式中,函数必须是内置函数,否则编译不过:
Go
package main
import "unsafe"
const (
a = "abc"
b = len(a)
c = unsafe.Sizeof(a)
)
func main(){
println(a, b, c)
}
执行后输出:
Go
abc 3 16
为什么unsafe.Sizeof(a)得到是的16?unsafe.Sizeof函数用于表示string 类型结构大小
因为 string 结构只存指针和长度,不存内容本体,string 结构大小本身为16 字节。
iota ------ 枚举神器
Go 没有 enum,但可以用 iota 构建枚举常量。
iota 是一个从 0 开始、每行递增 1 的计数器。
Go
package main
import "fmt"
func main() {
const (
a = iota //0
b //1
c //2
d = "ha" //独立值,iota += 1
e //"ha" iota += 1
f = 100 //iota +=1
g //100 iota +=1
h = iota //7,恢复计数
i //8
)
fmt.Println(a,b,c,d,e,f,g,h,i)
}
输出:
0 1 2 ha ha 100 100 7 8
这里需要注意:h = iota 会恢复计数,在前面行数基础上+1
实现枚举:
Go
const (
StatusInit = iota // 0
StatusRunning // 1
StatusSuccess // 2
StatusFailed // 3
)
位标志(常用于权限系统、标记位等):
Go
const (
FlagRead = 1 << iota // 1 << 0 → 1
FlagWrite // 1 << 1 → 2
FlagExecute // 1 << 2 → 4
)
再看个 iota 实例:
Go
package main
import "fmt"
const (
i=1<<iota
j=3<<iota
k
l
)
func main() {
fmt.Println("i=",i)
fmt.Println("j=",j)
fmt.Println("k=",k)
fmt.Println("l=",l)
}
执行后输出:
i= 1
j= 6
k= 12
l= 24
iota 表示从 0 开始自动加 1,所以 i=1<<0, j=3<<1(<< 表示左移的意思),即:i=1, j=6,这没问题,关键在 k 和 l,从输出结果看 k=3<<2,l=3<<3。
简单表述:
- i=1:左移 0 位,不变仍为 1。
- j=3 :左移 1 位,变为二进制 110,即 6。
- k=3 :左移 2 位,变为二进制 1100,即 12。
- l=3 :左移 3 位,变为二进制 11000,即 24。
注:<<n==*(2^n)。
常量的特点
| 特性 | 说明 |
|---|---|
| 不可修改 | 运行时不能更改值 |
| 编译期确定 | 值必须是编译期可确定的表达式 |
| 不能使用运行时函数 | 比如 time.Now() 不能用于 const |
| 只支持简单数据类型 | 数字、字符串、布尔值 |
| 表达式计算必须在编译期完成 | 如:const z = 3 * 5 |
非法示例:
Go
const t = time.Now() // ❌ 编译错误
常量的典型适用场景
| 场景 | 示例 |
|---|---|
| 标志位(bitmask) | 1 << iota |
| 系统枚举 | 状态、权限、类型 |
| 数学常量 | Pi、最大值 |
| 配置项 | 默认端口、超时值 |
| 避免魔法数字(magic number) | RetryTimes = 3 |
常量与变量的区别
| 点 | 常量 const | 变量 var |
|---|---|---|
| 是否可修改 | ❌ 不可修改 | ✔ 可修改 |
| 值确定时间 | 编译期 | 运行期 |
| 类型 | 可无类型 | 必须有类型 |
| 性能 | 更高,编译期优化 | 运行期读取 |
常量通常比变量更 安全、高效。
总结
Go 常量(const)特点:
-
编译期确定值
-
不可修改
-
支持无类型常量(最有特点)
-
支持 iota 自动递增,用来实现枚举
-
不允许使用运行时的函数结果