本文内容基于《Go语言核心编程》,李文塔著。
1. 语言陷阱
1.1 多值赋值和短变量声明
1.1.1 多值赋值
可以一次性声明多个变量,并可以在声明时赋值,而且可以省略类型:
// 合法的
var x, y int
var x, y int = 1, 2
var x, y = 1, 2
var x, y = 1, "test"
var (
x int
y string
)
// 非法的
var x int, y int = 1, 2
var x int, y string = 1, "test"
var x int, y int
var x int, y string
多值赋值的两种格式:
- 右边是一个返回多值的表达式,可以是返回多值的函数调用,也可以是range对map、slice等函数的操作,还可以是类型断言;
- 赋值的左边操作数和右边的单一返回值的表达式的个数一样,逐个从左向右依次对左边的操作数赋值。
// 函数调用
x, y = f()
// range
for k, v := range map {}
// 类型断言
v, ok := i.(xxxx)
// 左右个数一样
x, y, z = a, b, c
多值赋值语义:
- 对左侧操作数中的表达式、索引值进行计算和确定,首先确定左侧的操作数的地址,然后对右侧的赋值表达式进行计算,如果发现右侧的表达式计算引用了左侧的变量,则创建临时变量进行值拷贝,最后完成计算;
- 从左到右的顺序依次赋值。
func main() {
x := []int{1, 2, 3}
i := 0
i, x[i] = 1, 2
fmt.Println(i, x) // 1 [2 2 3]
x = []int{1, 2, 3}
i = 0
x[i], i = 2, 1
fmt.Println(i, x) // 1 [2 2 3]
x = []int{1, 2, 3}
i = 0
x[i], i = 2, x[i]
fmt.Println(i, x) // 1 [2 2 3]
x[0], x[0] = 1, 2
fmt.Println(x[0]) // 2
}
1.1.2 短变量的声明和赋值
短变量的声明和赋值是指在Go函数或类型方法内部使用:=声明并初始化变量,支持多值赋值,语法要约:
- 使用:=操作符,变量的定义和初始化同时完成;
- 变量名后不要跟任何类型名,Go编译器完全靠右边的值进行推导;
- 支持多值短变量声明赋值;
- 只能用在函数和类型方法的内部;
a := va
a, b := va, vb
Go语言的语法允许多值短变量声明和赋值的多个变量中,只要有一个是新变量就可以使用:=进行赋值。