Skip to content

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 创建枚举和位标志
  • 优先使用无类型常量以获得更好的灵活性
  • 为常量使用描述性的名称
  • 将相关常量组织在一起

本站内容仅供学习和研究使用。