在数学概念中,变量(variable)表示没有固定值且可改变的数。但从计算机系统实现角度来看,变量是一段或多段用来存储数据的内存。
作为静态类型语言,Go 变量总是有固定的数据类型,类型决定了变量内存的长度和存储格式。我们只能修改变量值,无法改变类型。
通过类型转换或指针操作,我们可用不同方式修改变量值,但这并不意味着改变了变量类型。
因为内存分配发生在运行期,所以在编码阶段我们用一个易于阅读的名字来表示这段内存。实际上,编译后的机器码从不使用变量名,而是直接通过内存地址来访问目标数据。保存在符号表中的变量名等信息可被删除,或用于输出更详细的错误信息。
定义
- 关键字 var 用于定义变量,和 C 不同,类型被放在变量名后。
- 运行时内存分配操作会确保变量自动初始化为二进制零值(zero value),避免出现不可预测行为。
- 如显式提供初始化值,可省略变量类型,由编译器推断。
var x int // 自动初始化为0
var y = false // 自动推断为bool类型
- 可一次定义多个变量,包括用不同初始值定义不同类型。
var x, y int // 相同类型的多个变量
var a, s = 100, "abc" // 不同类型初始化值
- 依照惯例,建议以组方式整理多行变量定义。
var (
x, y int
a, s = 100, "abc"
)
简短模式
func main() {
x := 100
a, s := 1, "abc"
}
简短模式(short variable declaration)有些限制:
- 定义变量,同时显式初始化。
- 不能提供数据类型。
- 只能用在函数内部。
简短定义在函数多返回值,以及 if/for/switch 等语句中定义局部变量非常方便。
简短模式并不总是重新定义变量,也可能是部分退化的赋值操作。
func main() {
x := 100
println(&x)
x, y := 200, "abc" // 注意: x退化为赋值操作,仅有y是变量定义
println(&x, x)
println(y)
}
退化赋值的前提条件是:最少有一个新变量被定义,且必须是同一作用域。
func main() {
x := 100
println(&x)
x := 200 // 错误: no new variables on left side of:=
println(&x, x)
}
func main() {
x := 100
println(&x, x)
{
x, y := 200, 300 // 不同作用域,全部是新变量定义
println(&x, x, y)
}
}
在处理函数错误返回值时,退化赋值允许我们重复使用 err 变量,这是相当有益的。
func main() {
f, err := os.Open("/dev/random")
// ...
buf := make([]byte, 1024)
n, err := f.Read(buf) // err退化赋值,n新定义
// ...
}
多变量赋值
在进行多变量赋值操作时,首先计算出所有右值,然后再依次完成赋值操作。
func main() {
x, y := 1, 2
x, y = y+3, x+2 // 先计算出右值y+3、x+2,然后再对x、y变量赋值
println(x,y)
}
赋值操作,必须确保左右值类型相同。
未使用错误
- 编译器将未使用局部变量当作错误。不要觉得麻烦,这有助于培养良好的编码习惯。
- 全局变量不会报错。