Go 语言常量
常量是在编译时就确定值且运行时不可改变的标识符。Go 语言中的常量提供了一种安全、高效的方式来定义不变的值。本章将详细介绍常量的声明、类型、特殊功能等。
📋 常量基础
常量声明
基本语法
go
package main
import "fmt"
func main() {
// 1. 显式类型常量
const name string = "Go语言"
const version float64 = 1.21
const isStable bool = true
const maxUsers int = 1000
fmt.Printf("语言: %s\n", name)
fmt.Printf("版本: %.2f\n", version)
fmt.Printf("稳定: %t\n", isStable)
fmt.Printf("最大用户数: %d\n", maxUsers)
// 2. 类型推断常量
const appName = "我的应用" // string
const port = 8080 // int
const timeout = 30.5 // float64
const debug = true // bool
fmt.Printf("应用: %s, 端口: %d\n", appName, port)
fmt.Printf("超时: %.1f秒, 调试: %t\n", timeout, debug)
}常量的特点
go
func main() {
const pi = 3.14159
// 常量在编译时确定
fmt.Printf("π = %.5f\n", pi)
// 常量不能修改
// pi = 3.14 // 错误!常量不能重新赋值
// 常量表达式在编译时计算
const (
radius = 5
area = pi * radius * radius // 编译时计算
circumference = 2 * pi * radius
)
fmt.Printf("半径: %d\n", radius)
fmt.Printf("面积: %.2f\n", area)
fmt.Printf("周长: %.2f\n", circumference)
}多常量声明
分组声明
go
func main() {
// 使用 const() 进行分组声明
const (
// 应用配置
AppName = "用户管理系统"
AppVersion = "1.0.0"
AppAuthor = "开发团队"
// 服务器配置
ServerHost = "localhost"
ServerPort = 8080
ServerSSL = false
// 数据库配置
DBHost = "127.0.0.1"
DBPort = 3306
DBName = "userdb"
DBUser = "admin"
DBTimeout = 30
)
fmt.Printf("应用信息: %s v%s by %s\n", AppName, AppVersion, AppAuthor)
fmt.Printf("服务器: %s:%d (SSL: %t)\n", ServerHost, ServerPort, ServerSSL)
fmt.Printf("数据库: %s:%d/%s (超时: %ds)\n", DBHost, DBPort, DBName, DBTimeout)
}省略值的声明
go
func main() {
const (
a = 1
b // b = 1 (继承上一个常量的值)
c // c = 1
d = 2
e // e = 2
f // f = 2
)
fmt.Printf("a=%d, b=%d, c=%d\n", a, b, c)
fmt.Printf("d=%d, e=%d, f=%d\n", d, e, f)
const (
red = "红色"
green = "绿色"
blue = "蓝色"
yellow // yellow = "蓝色" (继承上一个值)
)
fmt.Printf("颜色: %s, %s, %s, %s\n", red, green, blue, yellow)
}🔢 iota 枚举器
iota 基础用法
go
func main() {
// iota 是一个预声明的标识符,用于生成连续的整数常量
const (
Monday = iota // 0
Tuesday // 1
Wednesday // 2
Thursday // 3
Friday // 4
Saturday // 5
Sunday // 6
)
fmt.Printf("星期一: %d\n", Monday)
fmt.Printf("星期二: %d\n", Tuesday)
fmt.Printf("星期日: %d\n", Sunday)
// 每个 const 块中 iota 都重新开始
const (
January = iota + 1 // 1
February // 2
March // 3
)
fmt.Printf("一月: %d, 二月: %d, 三月: %d\n", January, February, March)
}iota 高级用法
跳过某些值
go
func main() {
const (
Read = 1 << iota // 1 << 0 = 1
Write // 1 << 1 = 2
Execute // 1 << 2 = 4
)
fmt.Printf("权限 - 读: %d, 写: %d, 执行: %d\n", Read, Write, Execute)
// 跳过某些值
const (
StatusOK = iota // 0
StatusWarning // 1
_ // 2 (跳过)
StatusError // 3
StatusFatal // 4
)
fmt.Printf("状态码 - OK: %d, Warning: %d, Error: %d, Fatal: %d\n",
StatusOK, StatusWarning, StatusError, StatusFatal)
}复杂的 iota 表达式
go
func main() {
// 使用 iota 进行复杂计算
const (
_ = iota // 0 (跳过)
KB = 1 << (10 * iota) // 1 << 10 = 1024
MB // 1 << 20 = 1048576
GB // 1 << 30 = 1073741824
TB // 1 << 40
)
fmt.Printf("存储单位:\n")
fmt.Printf("1 KB = %d 字节\n", KB)
fmt.Printf("1 MB = %d 字节\n", MB)
fmt.Printf("1 GB = %d 字节\n", GB)
fmt.Printf("1 TB = %d 字节\n", TB)
// 多个 iota 表达式
const (
bit0, mask0 = 1 << iota, 1<<iota - 1 // 1, 0
bit1, mask1 // 2, 1
bit2, mask2 // 4, 3
bit3, mask3 // 8, 7
)
fmt.Printf("位操作:\n")
fmt.Printf("bit0=%d, mask0=%d\n", bit0, mask0)
fmt.Printf("bit1=%d, mask1=%d\n", bit1, mask1)
fmt.Printf("bit2=%d, mask2=%d\n", bit2, mask2)
fmt.Printf("bit3=%d, mask3=%d\n", bit3, mask3)
}🎭 常量类型
有类型常量 vs 无类型常量
有类型常量
go
func main() {
// 显式指定类型的常量
const typedInt int = 42
const typedFloat float64 = 3.14
const typedString string = "类型化常量"
const typedBool bool = true
// 有类型常量必须与变量类型精确匹配
var i int = typedInt // 正确
// var i32 int32 = typedInt // 错误!类型不匹配
var i32 int32 = int32(typedInt) // 需要类型转换
fmt.Printf("有类型常量: %d, %g, %s, %t\n", typedInt, typedFloat, typedString, typedBool)
fmt.Printf("转换后的int32: %d\n", i32)
}无类型常量
go
func main() {
// 无类型常量(字面量常量)
const untypedInt = 42 // 无类型整数
const untypedFloat = 3.14 // 无类型浮点数
const untypedString = "无类型" // 无类型字符串
// 无类型常量可以赋值给兼容的类型
var i int = untypedInt
var i32 int32 = untypedInt
var i64 int64 = untypedInt
var f32 float32 = untypedFloat
var f64 float64 = untypedFloat
fmt.Printf("无类型整数赋值: int=%d, int32=%d, int64=%d\n", i, i32, i64)
fmt.Printf("无类型浮点数赋值: float32=%g, float64=%g\n", f32, f64)
// 无类型常量在运算中的精度
const huge = 1e1000 // 超出任何基本类型范围的常量
fmt.Printf("巨大的常量存在: %T\n", huge)
// 只有在赋值时才检查范围
// var x float64 = huge // 错误!超出 float64 范围
}常量的默认类型
go
import "reflect"
func main() {
// 无类型常量的默认类型
const (
intConst = 42 // 默认 int
floatConst = 3.14 // 默认 float64
complexConst = 1 + 2i // 默认 complex128
runeConst = 'A' // 默认 rune (int32)
stringConst = "hello" // 默认 string
boolConst = true // 默认 bool
)
// 查看变量类型
var i = intConst
var f = floatConst
var c = complexConst
var r = runeConst
var s = stringConst
var b = boolConst
fmt.Printf("int常量类型: %s\n", reflect.TypeOf(i))
fmt.Printf("float常量类型: %s\n", reflect.TypeOf(f))
fmt.Printf("complex常量类型: %s\n", reflect.TypeOf(c))
fmt.Printf("rune常量类型: %s\n", reflect.TypeOf(r))
fmt.Printf("string常量类型: %s\n", reflect.TypeOf(s))
fmt.Printf("bool常量类型: %s\n", reflect.TypeOf(b))
}🔧 常量表达式
编译时计算
go
import "math"
func main() {
// 常量表达式在编译时计算
const (
pi = 3.14159265358979323846
radius = 10
area = pi * radius * radius // 编译时计算
circumference = 2 * pi * radius // 编译时计算
)
fmt.Printf("π = %.15f\n", pi)
fmt.Printf("半径 = %d\n", radius)
fmt.Printf("面积 = %.2f\n", area)
fmt.Printf("周长 = %.2f\n", circumference)
// 可以使用的操作
const (
a = 2 + 3 // 算术运算
b = 10 / 3 // 整数除法
c = 10.0 / 3.0 // 浮点除法
d = 2 << 3 // 位运算
e = -5 // 一元运算
f = "hello" + "world" // 字符串连接
)
fmt.Printf("常量运算: a=%d, b=%d, c=%g, d=%d, e=%d, f=%s\n", a, b, c, d, e, f)
// 不能使用运行时函数
// const sqrt2 = math.Sqrt(2) // 错误!math.Sqrt 是运行时函数
}常量中的类型转换
go
func main() {
const (
// 常量中可以进行类型转换
floatPi = 3.14159
intPi = int(floatPi) // 截断为 3
stringNum = string(65) // 转换为字符 'A'
runeNum = rune(65) // 转换为字符 'A'
)
fmt.Printf("原始π: %g\n", floatPi)
fmt.Printf("整数π: %d\n", intPi)
fmt.Printf("字符65: %s\n", stringNum)
fmt.Printf("Rune65: %c\n", runeNum)
// 常量类型转换的限制
const bigInt = 1000000000000000000
// const overflow = int32(bigInt) // 错误!编译时检测溢出
const validInt32 = int32(1000) // 正确,在范围内
fmt.Printf("有效的int32常量: %d\n", validInt32)
}🎯 实际应用示例
配置常量
go
package main
import "fmt"
// 应用配置常量
const (
// 应用信息
AppName = "电商系统"
AppVersion = "2.1.0"
AppAuthor = "开发团队"
// 服务器配置
DefaultHost = "0.0.0.0"
DefaultPort = 8080
DefaultTimeout = 30
// 数据库配置
MaxConnections = 100
ConnectionTimeout = 5
QueryTimeout = 30
// 业务规则
MaxOrderItems = 50
MaxUserSessions = 5
SessionTimeout = 3600 // 秒
CacheExpiration = 1800 // 秒
)
func main() {
fmt.Printf("=== %s v%s ===\n", AppName, AppVersion)
fmt.Printf("开发团队: %s\n", AppAuthor)
fmt.Printf("\n服务器配置:\n")
fmt.Printf(" 地址: %s:%d\n", DefaultHost, DefaultPort)
fmt.Printf(" 超时: %d秒\n", DefaultTimeout)
fmt.printf("\n数据库配置:\n")
fmt.Printf(" 最大连接数: %d\n", MaxConnections)
fmt.Printf(" 连接超时: %d秒\n", ConnectionTimeout)
fmt.Printf(" 查询超时: %d秒\n", QueryTimeout)
fmt.Printf("\n业务规则:\n")
fmt.Printf(" 订单最大商品数: %d\n", MaxOrderItems)
fmt.Printf(" 用户最大会话数: %d\n", MaxUserSessions)
fmt.Printf(" 会话超时: %d秒\n", SessionTimeout)
}枚举常量
go
// 订单状态枚举
const (
OrderPending = iota // 0 - 待处理
OrderConfirmed // 1 - 已确认
OrderPaid // 2 - 已支付
OrderShipped // 3 - 已发货
OrderDelivered // 4 - 已送达
OrderCancelled // 5 - 已取消
OrderRefunded // 6 - 已退款
)
// 用户权限位标志
const (
PermissionRead = 1 << iota // 1 - 读权限
PermissionWrite // 2 - 写权限
PermissionDelete // 4 - 删除权限
PermissionAdmin // 8 - 管理权限
)
// 错误代码
const (
ErrCodeSuccess = 0
ErrCodeInvalidParam = 1001
ErrCodeUserNotFound = 1002
ErrCodePasswordWrong = 1003
ErrCodePermissionDenied = 1004
ErrCodeSystemError = 5000
)
func main() {
// 使用订单状态
currentStatus := OrderPaid
fmt.Printf("当前订单状态: %d\n", currentStatus)
// 使用权限位标志
userPermissions := PermissionRead | PermissionWrite // 3
hasReadPermission := userPermissions&PermissionRead != 0
hasDeletePermission := userPermissions&PermissionDelete != 0
fmt.Printf("用户权限: %d\n", userPermissions)
fmt.Printf("有读权限: %t\n", hasReadPermission)
fmt.Printf("有删除权限: %t\n", hasDeletePermission)
// 使用错误代码
errorCode := ErrCodeUserNotFound
errorMessage := getErrorMessage(errorCode)
fmt.Printf("错误代码: %d, 错误信息: %s\n", errorCode, errorMessage)
}
func getErrorMessage(code int) string {
switch code {
case ErrCodeSuccess:
return "操作成功"
case ErrCodeInvalidParam:
return "参数无效"
case ErrCodeUserNotFound:
return "用户不存在"
case ErrCodePasswordWrong:
return "密码错误"
case ErrCodePermissionDenied:
return "权限不足"
case ErrCodeSystemError:
return "系统错误"
default:
return "未知错误"
}
}数学和物理常量
go
import "math"
// 数学常量
const (
Pi = 3.14159265358979323846
E = 2.71828182845904523536
Phi = 1.61803398874989484820 // 黄金比例
)
// 物理常量
const (
SpeedOfLight = 299792458 // 光速 (m/s)
GravityEarth = 9.80665 // 地球重力加速度 (m/s²)
AvogadroNumber = 6.02214076e23 // 阿伏伽德罗常数
PlanckConstant = 6.62607015e-34 // 普朗克常数 (J⋅s)
)
// 单位转换常量
const (
// 长度单位 (转换为米)
Millimeter = 0.001
Centimeter = 0.01
Meter = 1.0
Kilometer = 1000.0
// 时间单位 (转换为秒)
Nanosecond = 1e-9
Microsecond = 1e-6
Millisecond = 1e-3
Second = 1.0
Minute = 60.0
Hour = 3600.0
Day = 86400.0
)
func main() {
// 使用数学常量
radius := 5.0
area := Pi * radius * radius
circumference := 2 * Pi * radius
fmt.Printf("圆形计算 (半径=%.1f):\n", radius)
fmt.Printf(" 面积: %.2f\n", area)
fmt.Printf(" 周长: %.2f\n", circumference)
// 使用物理常量
distance := 1.0 * Kilometer // 1公里
time := distance / SpeedOfLight
fmt.Printf("\n光传播计算:\n")
fmt.Printf(" 距离: %.0f米\n", distance)
fmt.Printf(" 光传播时间: %.2e秒\n", time)
// 单位转换
lengthInCm := 150.0 // 150厘米
lengthInM := lengthInCm * Centimeter
timeInMs := 500.0 // 500毫秒
timeInS := timeInMs * Millisecond
fmt.Printf("\n单位转换:\n")
fmt.Printf(" %.0f厘米 = %.2f米\n", lengthInCm, lengthInM)
fmt.Printf(" %.0f毫秒 = %.3f秒\n", timeInMs, timeInS)
}🎓 小结
本章我们深入学习了 Go 语言的常量:
- ✅ 常量声明:const 关键字、类型推断、分组声明
- ✅ iota 枚举器:自动递增、复杂表达式、位标志
- ✅ 常量类型:有类型常量 vs 无类型常量、默认类型
- ✅ 常量表达式:编译时计算、类型转换
- ✅ 实际应用:配置常量、枚举、数学物理常量
常量是 Go 语言中重要的特性,正确使用常量可以让代码更安全、更高效、更易维护。
接下来,我们将学习 Go 语言运算符,掌握各种运算符的使用方法。
常量使用建议
- 使用常量定义配置值和魔术数字
- 利用 iota 创建枚举和位标志
- 优先使用无类型常量以获得更好的灵活性
- 为常量使用描述性的名称
- 将相关常量组织在一起