Go 语言变量¶
变量为具有类型的存储位置命名,其值可以在允许范围内改变。
本篇介绍 var、短变量声明、类型推导、多重赋值、零值、指针和变量生命周期。
var 声明¶
只声明类型时得到零值:
声明时也可初始化并由表达式推导类型:
多个同类变量可成组声明,但不要为了减少行数牺牲含义:
短变量声明¶
函数体内可以使用 :=:
它不能用于包级声明。 左侧至少一个名称必须在当前词法块中是新变量:
第二次使用 := 合法,因为 nextErr 是当前块的新变量。
指定类型与推导类型¶
small 是 int8,inferred 通常是 int。
当类型属于外部协议、单位或 API 契约的一部分时,应显式写出类型;局部实现细节可让编译器推导。
多重赋值与交换¶
右侧先求值,因此不需要临时变量。 多返回值常用于“结果加错误”或映射、类型断言的“值加状态”模式。
空白标识符¶
_ 接收并丢弃值:
这段代码可运行,但忽略解析错误通常不是好实践。 空白标识符适合明确忽略不需要且无风险的结果,不能作为系统性吞错方案。
指针变量¶
&count 取得地址,*pointer 访问指向的值。
是否分配到堆由编译器逃逸分析决定,不由 new 或 & 的表面写法简单决定。
new 与复合字面量¶
new(T) 返回指向 T 零值的 *T。
结构体通常使用 &T{...},因为它可同时表达字段初始化;不要为了“像其他语言构造对象”而滥用 new。
差异示例一:var 与 :=¶
var 可用于包级、可显式类型并自然表达零值;:= 仅用于函数内,适合紧邻首次使用的局部初始化。
二者没有普遍性能优劣,选择应服务于作用域和可读性。
差异示例二:遮蔽与重新赋值¶
块内 value := 20 声明了新变量,外层仍为 10。
若希望修改外层变量,应写 value = 20;错误使用 := 是常见逻辑缺陷。
差异示例三:值参数与指针参数¶
值参数修改副本,指针参数可修改调用者存储。 但指针不自动表示“更快”;小值直接复制通常更简单,是否使用指针应考虑修改语义、大小和 nil 状态。
包级变量边界¶
包级变量在包初始化时创建,生命周期贯穿进程。 不可变配置可用常量表达;可变依赖和缓存应评估并发安全、测试隔离和初始化失败处理。 不要把环境变量读取、数据库连接和请求状态都隐藏在全局变量中。
常见错误¶
- 在内层使用
:=意外遮蔽err或结果变量。 - 为消除“声明未使用”而随意写
_ = value,掩盖未完成代码。 - 返回局部变量指针后误以为一定悬空;Go 会保证其生命周期,但仍需考虑共享和逃逸成本。
- 使用包级可变变量保存请求级状态,引发数据竞争。
- 用指针表示所有值,产生不必要的 nil 分支和别名关系。
工程实践¶
- 将变量声明放在最小必要作用域,并靠近首次使用位置。
- 名称表达单位和语义,如
timeout、sizeBytes,不要只写x。 - 对
err遮蔽保持警惕,尤其在if初始化语句和循环中。 - 共享可变变量必须通过锁、原子操作或明确所有权同步。
- 让结构体零值尽可能有效,减少额外布尔状态和初始化分支。
- 通过编译器和基准判断逃逸及性能,不凭直觉重写为指针。
变量的关键不只是声明语法,还包括作用域、所有权、共享关系和生命周期。