求值顺序

包级变量声明语句中的表达式求值顺序

  • 按照变量的声明顺序,从上到下,从左到右,进行求值
  • 如果 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
}
  1. 查找没有依赖项的变量将其求值,这一轮中是 d,此时只有 [d=3]
  2. 查找没有依赖项的变量进行求值,这一轮中 a 还是不符合,但是 b 符合了,所以现在是 [b=4,d=4]
  3. 查找没有依赖项的变量进行求值,这一轮中是 _,此时 [b=4,d=5]
  4. 查找没有依赖项的变量进行求值,这一轮中是 c,此时 [b=4,c=6,d=6]
  5. 查找没有依赖项的变量进行求值,这一轮中是 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
  1. 左边没有要处理的表达式,右侧有,那么第一个位置就是 n0+n1,因为 n0 和 n1 已经存在了初始化的内容了,所以这里直接就是 3,no = 1,这时 n0 和 n1 还是 1 2,因为还没有赋值呢。
  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 页