go中只有var声明和短变量声明(:=),二者行为、作用域、初始化规则完全不同;var用于包级变量、显式类型声明或只声明不初始化,:=仅限函数内且必须至少有一个新变量名,混用易致遮蔽或零值陷阱。

Go 里没有“变量定义”和“变量声明”的语义区分,只有 var 声明和短变量声明(:=),且二者行为、作用域、初始化规则完全不同——混用容易导致未预期的变量遮蔽或零值陷阱。
什么时候必须用 var 声明
var 是唯一能用于包级作用域声明变量的方式;函数内也支持,但语义更明确:它不依赖类型推导,且允许只声明不初始化(得到零值)。
- 包级变量(如配置、全局计数器)必须用
var,例如:var DefaultTimeout = 30 * time.Second
- 需要显式指定类型但暂不赋值(比如后续条件分支才赋值):
var conn net.Conn // 不写 :=,否则报错:cannot use := outside function
- 声明多个同类型变量时更紧凑:
var a, b, c int
(而a, b, c := 1, 2, 3要求右侧值数量、类型都严格匹配)
为什么 := 在 if/for 语句里最常用
:= 是短变量声明,本质是“声明 + 初始化”,只在函数内部可用,且会自动推导类型。它在控制流中能自然绑定临时值,避免污染外层作用域。
- 常见于错误检查:
if err := doSomething(); err != nil { ... }——这里的err只在该if块内有效 - 注意:如果
err已在外部声明过,:=仍可使用,但仅当至少有一个新变量名出现时才合法(否则编译报错no new variables on left side of :=) - for range 中常用:
for i, v := range data { ... },i和v都是新声明的局部变量
var 和 := 混用导致的遮蔽问题
函数内若先用 var err error 声明,再在某个 if 里写 if err := call(); err != nil,实际创建了一个新的 err 局部变量,外层 err 保持未修改——这是最典型的“误以为错误被捕获,实则静默丢弃”场景。
- 现象:函数返回前检查
err != nil总是 false,但上游调用者收不到错误 - 修复方式一:统一用
var err error声明,所有赋值用=:var err error if err = doA(); err != nil { return err } if err = doB(); err != nil { return err } - 修复方式二:用
:=但确保首次声明,后续分支改用=或重构逻辑
结构体字段、切片、map 的零值陷阱
Go 变量默认初始化为零值,这对指针、slice、map、channel 尤其关键:它们的零值是 nil,不是空集合。直接操作会 panic。
-
var s []int→s是 nil slice,len(s)为 0,但s = append(s, 1)可安全运行(append 内部会 realloc) -
var m map[string]int→m是 nil map,m["k"] = 1会 panic;必须先m = make(map[string]int) -
var p *int→p是 nil 指针,解引用*p会 panic;需配合new()或取地址:p = new(int) // or p = &someInt
真正难的不是记住几种写法,而是每次敲 := 时,下意识问一句:这个变量名是不是第一次出现?它的作用域边界在哪里?有没有可能意外遮蔽外层同名变量?
golang免费学习笔记(深入):立即使用
在学习笔记中,你将探索golang的核心概念和高级技巧!











