函数内部声明局部变量优先用 :=,因其自动推导类型、简洁且符合惯用法;var 适用于显式指定类型、暂不赋值或批量声明等场景。

Go里声明局部变量用 := 还是 var?
函数内部声明局部变量,优先用 :=。它自动推导类型、简洁且符合Go惯用法;var 更适合需要显式指定类型、声明但暂不赋值、或批量声明的场景。
常见错误是试图在函数外用 :=(会报 non-declaration statement outside function body),或者在已声明的变量上重复用 :=(会报 no new variables on left side of :=)。
-
:=必须至少有一个新变量名,右边表达式不能全是对已有变量的重新赋值 - 如果只是想更新已有变量,用
= - 多个变量可一次声明:
a, b := 1, "hello",类型各自推导 - 需要零值占位或延迟初始化时,用
var x int,此时x被设为0
哪些地方不能用 := 声明局部变量?
不是所有语句块都支持 :=。它只在函数体内、for/if/switch 的子语句块中合法;在包级作用域、struct 字段、interface 方法签名、const 块里一律禁止。
典型错误示例:if err := doSomething(); err != nil { ... } 是对的,但写成 if err := doSomething(); err != nil { var msg := "fail" } 就会报错——因为 := 不能出现在复合语句的嵌套块里(除非该块是函数体)。
- for 循环的 init 语句中可用:
for i := 0; i - if 条件前的短声明可用:
if v := getValue(); v > 0 - switch 的 init 语句也可用:
switch x := getVal(); x - 但 switch 分支内的
case块里再用:=,必须确保有新变量名
局部变量的作用域和生命周期怎么算?
Go 的局部变量作用域由花括号 {} 决定:从声明处开始,到最近的右大括号结束。它不因是否被 return 或 panic 而提前销毁;只要变量可能被后续代码访问,就会存活到作用域末尾。
注意:如果变量逃逸到堆(比如取地址后传给全局变量或 goroutine),它的生命周期会延长,但作用域规则不变——你依然不能在作用域外通过名字访问它。
- 在
if块内声明的变量,在if外不可见 - for 循环每次迭代都会新建变量(不是复用),所以
for i := range s { go func(){ println(i) }() }通常打印最后一个i值 - 想捕获当前迭代值,得显式传参:
go func(v int){ println(v) }(i)
为什么有时必须用 var 而不能用 :=?
当你要声明一个零值变量、类型无法从右侧推导、或需要和已有变量同名但不同作用域时,var 不可替代。比如接收 JSON 到结构体指针、声明 channel 或 map 类型、或在 defer 中引用尚未赋值的变量。
典型例子:var buf bytes.Buffer —— 如果写成 buf := bytes.Buffer{},类型是 bytes.Buffer 实例;而 var buf *bytes.Buffer 明确要的是指针类型,这时 := 无法直接达成。
- 声明未初始化的 slice:
var s []int(s为 nil) vss := []int{}(s是空 slice,非 nil) - 声明带 cap 的 slice:
var s = make([]int, 0, 10),不能用:=简化,因为make返回值类型需明确 - 函数参数或返回值类型声明必须用
var风格(实际是类型标注,非声明语句)
局部变量看似简单,但 := 的“新变量”约束、作用域嵌套规则、以及逃逸分析带来的行为差异,是很多隐性 bug 的源头。写的时候多看一眼编译器报错信息里的“no new variables”,基本就能避开大半坑。
golang免费学习笔记(深入):立即使用
在学习笔记中,你将探索golang的核心概念和高级技巧!











