Go语言之估值顺序

The Order of Variable Expression Valuation In Golang

Posted by alovn on June 11, 2021

按依赖顺序进行估值

1
2
3
4
5
6
7
8
9
10
var (
    a1 = f("a1", a2)
    a2 = f("a2", a3)
    a3 = f("a3", 3)
    a4 = f("a4", 4)
)
func f(s string, a int) int {
    fmt.Println(s)
    return a
}

包级变量会按依赖顺序进行估值, 比如a1依赖a2,那么a1初始化就晚于a2。上面的初始化顺序为:a3, a4, a2, a1。其中a3与a4的估值顺序依赖于编译器的实现。

赋值表达式估值和赋值执行顺序

方法、通道、函数调用的顺序取决于它们在代码中出现的先后顺序。

一条赋值语句的执行分为估值和实施两个阶段。

  1. 估值在代码执行之前完成。(变量或容器索引)。
  2. 在第二个阶段中发生的赋值操作不会对在第一个阶段结尾已经确定的赋值操作有影响。
  3. 赋值语句右边先被估值。

示例一:

1
2
3
4
x := []int{0, 0}
i := 0
i, x[i] = 1, 2
fmt.Println(x) //[2 0]

这里的 x[i] 在赋值之前先被估值为0, 所以x[0]被赋值为2。

示例二:

1
2
3
4
5
6
x := []int{2, 3, 5, 7, 11}
t := x[0]
var i int
for i, x[i] = range x{}
x[i] = t
fmt.Println(x) //[3 5 7 11 2]

这个示例代码比较有意思,它将切片中的所有元素左移动了一位。切片的索引先被估值,因为i为零,所以for循环的左边为 i, x[0], 右边为 0, 2。那么第一次循环结果为 i = 0, x[0] = 2。

第二次for循环左边为 i, x[0],因为i被赋值为0。循环右边为 1,3。此时 i = 1, x[0] = 3。

循环完毕后 x 为 [3, 5, 7, 11, 11]。

尽管使用复杂的多赋值语句是合法的,但实际使用是不推荐的,因为代码可读性不高,还会使编译速度变慢,执行效率也略低。