4.4 KiB
tags, create time
| tags | create time | ||||
|---|---|---|---|---|---|
|
2026-06-07 15:00 |
Go 语言变量
概述
Go 提供三种变量声明方式:var、类型推断、:= 短声明。本文覆盖零值规则、多变量赋值、生命周期和常见陷阱。
正文
为什么 Go 的变量总有"默认值"?
在 C / C++ 中,未初始化的局部变量是垃圾值——读它会导致未定义行为。Go 做了一个安全选择:所有变量都有确定的零值。
[!note] 📝 Go 零值表
| 类型 | 零值 |
|---|---|
int, int32, int64, float64 等数值类型 |
0 |
bool |
false |
string |
""(空字符串) |
| 指针、slice、map、chan、func、error | nil |
var i int // i == 0
var f float64 // f == 0.0
var b bool // b == false
var s string // s == ""
var p *int // p == nil
var m map[string]int // m == nil
var sl []int // sl == nil
[!warning] ⚠️ nil 类型陷阱
nil不是万能值。不同类型有各自不同的nil类型:*int的 nil 不等于[]int的 nil。比较时务必类型一致。
三种声明方式
方式一:var + 类型 + 初始化
var a string = "Hello" // 显式类型 + 初始化
var b int // 不初始化 → 零值 0
var c bool // 不初始化 → 零值 false
方式二:var + 类型推断(省略类型)
var d = true // 编译器推断为 bool
方式三::= 短声明(最常用)
e := 123 // 编译器推断为 int
f := "hello" // 编译器推断为 string
[!tip] 💡 首选
:=在函数体内,:=是最常用的声明方式——简洁且不易出错。但它只能用于函数体内,不能用于包级别的变量声明。
[!question] ❓ 思考 下面这段代码会编译通过吗?为什么?
var x int x := 5 // ?
多变量声明与并行赋值
Go 支持一行声明多个变量:
// 同类型多变量
var a, b, c int
// 类型推断
var d, e = 123, "hello"
// 短声明(仅限函数内)
f, g := 456, true
并行赋值是 Go 的一大亮点——右侧先全部求值,再一次性赋给左侧:
x, y := 1, 2
x, y = y, x // 交换!x 变成 2,y 变成 1
这也被广泛用于处理多返回值函数:
val, err := GetValue()
if err != nil {
// 处理错误
}
[!note] 📝 并行 vs 顺序 在
a[i], a[j] = a[j], a[i]中,Go 保证i和j的值在赋值前就被求值好,所以即使i == j也能正确工作。这是与许多语言的关键区别。
空白标识符 _
当你不需要某个值时,用 _ 丢弃:
_, b := 5, 7 // 丢弃 5,只保留 b == 7
_, err := GetValue()
if err != nil {
// 只需要错误,不需要返回值
}
[!warning] ⚠️
_不是变量_是一个只写占位符,你不能读取它的值,也不能对它做任何操作。每次使用_都会创建一个新的丢弃槽。
变量声明 vs 赋值
var x int
x := 5 // ❌ 编译错误:no new variables on left side of :=
x = 5 // ✅ 正确:给已声明的变量重新赋值
关键点:
:=必须在左侧引入至少一个新变量=只是赋值,不能用来声明新变量- 在同一代码块中,同名变量不能被
:=重复声明
未使用变量的陷阱
Go 编译器强制要求:声明了就必须使用。
func main() {
var a string = "abc"
fmt.Println("hello") // ❌ 编译错误:a declared but not used
}
修复方法:使用这个变量,或者用 _ 替代。
[!note] 📝 全局变量例外 包级别声明的变量允许不使用,但函数体内的局部变量不行。这是一个常见的新手坑。
生命周期
| 作用域 | 生命周期 |
|---|---|
| 全局变量(包级) | 程序启动到退出 |
| 局部变量(函数内) | 函数调用开始到结束(除非发生逃逸到堆) |
var globalVar int // 程序整个生命周期存在
func main() {
localVar := 42 // 函数返回后销毁(可能逃逸到堆)
_ = localVar
}
[!info] ℹ️ 逃逸分析 如果局部变量的地址被返回或被闭包捕获,Go 的逃逸分析会将它分配到堆上而非栈上,这样函数返回后它依然有效。具体机制见「逃逸分析」专题。