求值顺序
包级变量声明语句中的表达式求值顺序
- 按照变量的声明顺序,从上到下,从左到右,进行求值
- 如果 a 求值时有依赖项 b,或者是间接的依赖项 b,那么先求值 b
- 在求值的过程中会一直对于变量是否拥有依赖项进行查找,直到查询到没有依赖项的变量将其求值,然后重复这个查找,最后全部求值。
- 同一个包不同文件的处理,原则上如果 a 文件在 b 文件前面,那么 a 文件中的所有变量求值比 b 文件中的更早,除非 a 文件变量依赖了 b 中的变量。
var (
a = c + b
b = f()
_ = f()
c = f()
d = 3
)
func f() int {
d ++
return d
}
- 查找没有依赖项的变量将其求值,这一轮中是 d,此时只有 [d=3]
- 查找没有依赖项的变量进行求值,这一轮中 a 还是不符合,但是 b 符合了,所以现在是 [b=4,d=4]
- 查找没有依赖项的变量进行求值,这一轮中是 _,此时 [b=4,d=5]
- 查找没有依赖项的变量进行求值,这一轮中是 c,此时 [b=4,c=6,d=6]
- 查找没有依赖项的变量进行求值,这一轮中是 a,此时 [a=10,b=4,c=6,d=6]
输出 10 4 6 6
普通求值顺序
这包括了,函数,方法,channel 中的求值顺序。
- 规定是从左到右
y[f()],ok = g(h(),i()+x[j()], <-c),k()
这个语句的求值顺序就是 f() h() i() j() x[] <-c g() k()
普通值求值顺序和包级变量求值依赖顺序一起使用的时候,包级变量优先级更高,并且它在导入包的时候就已经求值了,而普通的求值顺序只有调用的时候才会求值。
赋值语句中的求值顺序
赋值语句求值有两个阶段 --- “先算后赋”
- 对等号左边的下标表达式,指针解引用表达式,以及等号右边的表达式,从左到右的依次求值
- 按照从左到右的顺序将变量进行赋值
例如
n0 := 1
n1 := 2
n0,n1 = n0+n1,n0
- 左边没有要处理的表达式,右侧有,那么第一个位置就是 n0+n1,因为 n0 和 n1 已经存在了初始化的内容了,所以这里直接就是 3,no = 1,这时 n0 和 n1 还是 1 2,因为还没有赋值呢。
- 开始赋值:右侧一个是 3 一个是 1,那么最新的 no 和 n1 就是 3 1
switch select 中的表达式的求值顺序
这里主要想说一下惰性求值:就是只有需求的时候才会进行求值
func f(n int)int{
return n
}
func main(){
switch f(2) {
case f(1),f(2),f(3):
fmt.Println("--")
}
}
首先先求值的是 switch 后面的 f (2)
然后对 f(1) f(2) 求值;f(3) 不会求值,因为 f (2) 已经满足了要求。
在 select case 中,如果 case 中存在表达式,最开始会依次计算所有的表达式,只有一种除外,收 case 中,位于左侧的表达式,它会在接受数据之前才会计算,然后赋值。
参考资料
- https://go.dev/ref/spec#Order_of_evaluation
- https://book.douban.com/subject/35720728/ 132 页 - 142 页