Files
cs-note/hzh/GolangStar/Go语言基础/Go语言变量.md
T

4.4 KiB
Raw Blame History

tags, create time
tags create time
go
golang
go基础语法
变量
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 的逃逸分析会将它分配到堆上而非栈上,这样函数返回后它依然有效。具体机制见「逃逸分析」专题。