目录

Go 变量与常量

变量和常量是编程中最基本的概念。Go 语言提供了灵活的变量声明方式,同时通过严格的编译检查来避免常见的错误。本篇将全面讲解 Go 中变量和常量的声明、命名规范、零值概念以及 iota 枚举器的用法。

变量声明

使用 var 关键字

Go 中使用 var 关键字声明变量,语法为 var 变量名 类型

package main

import "fmt"

func main() {
    var name string     // 声明一个 string 类型变量
    var age int         // 声明一个 int 类型变量
    var score float64   // 声明一个 float64 类型变量

    name = "张三"
    age = 25
    score = 95.5

    fmt.Println("姓名:", name)
    fmt.Println("年龄:", age)
    fmt.Println("分数:", score)
}

声明时初始化

可以在声明变量的同时赋予初始值,Go 会自动推导类型:

package main

import "fmt"

func main() {
    var name = "李四"        // 类型推导为 string
    var age = 30             // 类型推导为 int
    var pi = 3.14159         // 类型推导为 float64
    var isStudent = false    // 类型推导为 bool

    fmt.Printf("%T %T %T %T\n", name, age, pi, isStudent)
}

显式指定类型

如果需要明确指定类型(而非让编译器推导),可以这样写:

var count int = 100
var price float32 = 9.99

多变量声明

同时声明多个变量:

package main

import "fmt"

func main() {
    // 方式一:逐个声明
    var a, b, c int
    a, b, c = 1, 2, 3
    fmt.Println(a, b, c)

    // 方式二:同时初始化
    var x, y, z = 10, 20, 30
    fmt.Println(x, y, z)

    // 方式三:分组声明
    var (
        name    string = "王五"
        age     int    = 28
        city    string = "北京"
        isVip   bool   = true
    )
    fmt.Println(name, age, city, isVip)
}

短变量声明

在函数内部,可以使用 := 进行短变量声明,Go 会自动推导类型:

package main

import "fmt"

func main() {
    name := "赵六"       // 等价于 var name string = "赵六"
    age := 22            // 等价于 var age int = 22
    isMarried := false   // 等价于 var isMarried bool = false

    fmt.Println(name, age, isMarried)
}

短变量声明的限制

  • 只能在函数内部使用,包级变量必须用 var
  • 至少有一个新变量(如果变量已存在,则只赋值不重新声明):
package main

import "fmt"

func main() {
    x := 10
    y := 20

    // x 已存在,y 是新变量,合法
    x, y := 30, 40
    fmt.Println(x, y) // 输出: 30 40
}

变量命名规范

Go 的变量命名遵循以下规则:

  • 由字母、数字、下划线组成,但不能以数字开头。
  • 区分大小写:nameName 是不同的变量。
  • 推荐使用驼峰命名法(camelCase)。

首字母决定可见性

package user

// 首字母大写 —— 导出,其他包可访问
var DefaultRole = "guest"

// 首字母小写 —— 非导出,仅本包可访问
var maxLoginAttempts = 5

命名建议

  • 局部变量尽量用短名称:inerrctx
  • 作用域越大,名称越要有意义:userCountn 更好。
  • 布尔变量常用 ishascan 前缀:isValidhasError

零值概念

Go 中声明变量但未显式赋值时,变量会被赋予其类型的零值

类型 零值
int, int8, int16, int32, int64 0
uint, uint8, uint16, uint32, uint64 0
float32, float64 0.0
bool false
string ""(空字符串)
指针、函数、接口、slice、channel、map nil
package main

import "fmt"

func main() {
    var i int
    var f float64
    var b bool
    var s string
    var p *int

    fmt.Printf("int: %d\n", i)           // 0
    fmt.Printf("float64: %f\n", f)       // 0.000000
    fmt.Printf("bool: %t\n", b)          // false
    fmt.Printf("string: %q\n", s)        // ""
    fmt.Printf("pointer: %v\n", p)       // <nil>
}

零值设计的好处是:变量声明后即可安全使用,不需要额外的初始化代码。

常量声明

常量使用 const 关键字声明,其值在编译时确定,不可修改:

package main

import "fmt"

func main() {
    const pi = 3.14159265
    const appName = "MyApp"
    const maxRetry = 3

    // pi = 3.14  // 编译错误:不能修改常量
    fmt.Println(pi, appName, maxRetry)
}

常量分组

const (
    StatusPending  = "pending"
    StatusRunning  = "running"
    StatusComplete = "complete"
    StatusFailed   = "failed"
)

无类型常量

Go 的常量可以没有显式类型,称为"无类型常量",它们可以兼容更多类型:

package main

import "fmt"

const threshold = 100 // 无类型常量

func main() {
    var a int = threshold     // 可以赋给 int
    var b float64 = threshold // 可以赋给 float64
    var c int64 = threshold   // 可以赋给 int64
    fmt.Println(a, b, c)
}

iota 枚举器

iota 是 Go 的特殊常量生成器,每出现一次 iota,其值自动递增 1。它在常量组中从 0 开始计数。

基本用法

package main

import "fmt"

const (
    a = iota // 0
    b = iota // 1
    c = iota // 2
    d = iota // 3
)

func main() {
    fmt.Println(a, b, c, d) // 输出: 0 1 2 3
}

在同一常量组中,iota 可以省略不写(会自动沿用):

const (
    a = iota // 0
    b        // 1
    c        // 2
    d        // 3
)

实际应用:星期枚举

package main

import "fmt"

const (
    Sunday    = iota // 0
    Monday           // 1
    Tuesday          // 2
    Wednesday        // 3
    Thursday         // 4
    Friday           // 5
    Saturday         // 6
)

func main() {
    fmt.Println("Sunday =", Sunday)   // 0
    fmt.Println("Monday =", Monday)   // 1
    fmt.Println("Friday =", Friday)   // 5
    fmt.Println("Saturday =", Saturday) // 6
}

实际应用:文件大小单位

package main

import "fmt"

const (
    B  = 1 << (iota * 10) // 1
    KB                     // 1024
    MB                     // 1048576
    GB                     // 1073741824
    TB                     // 1099511627776
)

func main() {
    fmt.Printf("B  = %d\n", B)
    fmt.Printf("KB = %d\n", KB)
    fmt.Printf("MB = %d\n", MB)
    fmt.Printf("GB = %d\n", GB)
    fmt.Printf("TB = %d\n", TB)
}

iota 跳过值

使用 _ 可以跳过某些 iota 值:

package main

import "fmt"

const (
    A = iota // 0
    _        // 1(跳过)
    B = iota // 2
    C        // 3
)

func main() {
    fmt.Println(A, B, C) // 输出: 0 2 3
}

iota 配合表达式

package main

import "fmt"

const (
    One   = iota + 1 // 1
    Two              // 2
    Three            // 3
    Four             // 4
)

func main() {
    fmt.Println(One, Two, Three, Four) // 输出: 1 2 3 4
}

未使用变量的编译错误

Go 编译器严格要求:声明但未使用的变量会导致编译失败。这一设计避免了遗留无用变量的问题。

package main

import "fmt"

func main() {
    x := 10
    // fmt.Println("Hello")
    // 编译错误:x declared but not used
}

如果遇到确实需要声明但暂时不使用的变量,可以用 _ 丢弃:

package main

import "fmt"

func main() {
    _ = 10 // 不会报错

    // 函数返回多个值时,丢弃不需要的
    // result, _ := someFunc()
    fmt.Println("编译通过")
}

总结

本篇全面介绍了 Go 中变量和常量的使用方式。变量可以通过 var:= 声明,未赋值时自动获得零值;常量通过 const 声明,配合 iota 可以方便地生成枚举值。Go 通过严格的编译检查(未使用变量报错、常量不可修改)来保证代码质量。命名方面,首字母的大小写决定了标识符的可见性,这是 Go 独特的访问控制方式。