Go 表达式估值顺序规则

包级变量按依赖顺序进行估值

包级变量的估值顺序按照依赖顺序进行估值,比如var a f[b]依赖于var b = n的初始化,那么a就较晚于b进行估值

var (
f4 = print("f4", f3)
f3 = print("f3", f1)
f2 = print("f2")
f1 = print("f1")
)
func print(s ...interface{}) string {
fmt.Println(s...)
return ""
}

以上初始化顺序为

f2
f1
f3
f4

f3 依赖于f1的初始化,f4依赖f3的初始化,所以初始化顺序为f1->f3->f4
至于f1和f2的估值顺序在go白皮书中并未指定,这取决于不同的编译器实现

一些确切的估值顺序

go白皮书规定:

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

其他的一些情况都取决于不同编译器实现,不保证顺序

赋值语句的赋值顺序

赋值语句的赋值顺序是相对较难理解的地方,以及在go标准实现上存在一些争议的地方
https://github.com/golang/go/issues/15620

按照我的理解是

  1. 估值都是在具体代码执行前进行,容器索引等估值在赋值语句执行前进行
  2. 赋值语句不会对已经确定的赋值操作有影响
  3. 赋值语句右边首先估值

以下是go101中的几个demo 以及我的分析:

一、

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

按照规则1,x[i]索引在赋值前进行估值,为0,固x[0]为2,而不是x[1],比较简单

二、



m := map[string]int{"Go": 0}
s := []int{1, 1, 1}
olds := s
n := 2
p := &n
s, m["Go"], *p, s[n] = []int{2, 2, 2}, s[1], m["Go"], 5
fmt.Println(m, s, n) // map[Go:1] [2 2 2] 0
fmt.Println(olds)    // [1 1 5]

这个案例相对麻烦

右边

按照规则3,可以确定赋值语句右边分别为
[]int{2,2,2} 1 0 5

左边

  1. n 应该为2
  2. *p = n = 0
  3. m[“Go”]=1,那么m=map{"GO":1}
  4. 重点在于s与s[n]的问题,是s和s[n]的关系,是s先还是s[n]先呢?
    其实都不是,根据规则2我们可以知道,两者不应该有关联,可以如下思考,在估值前,s与s[n]两者的s都指向[]int{1,1,1}所在地址,s[n]为其中第三个元素,然后执行s= []int{2, 2, 2},那么s所在的地址指向一块新的内存区域,但是s[n]中的s还是指向之前的那片内存地址,可以看作有个临时变量在估值前就进行了接收该地址内容,已经确定了,那么此时更改之前那片内存区域的第2(n)个元素为5,元素更改为[]int{1,1,5},由于olds变量始终指向之前那片区域,所以olds=[]int{1,1,5}

其他例子

demo

结合上边的例子,剩下的就相对容易理解了

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]

上边例子可以将切片的顺序向左移位1,非常有趣

分析

根据规则1,索引在估值前求值,那么for循环的左边为i,x[0],for循环的右边为0,2,那么第一次循环完毕i=0``x[0]=2,第二次循环for循环左边为i,x[0]注意这里还是x[0],因为i为0,for循环右边为1,3,循环完毕i=1``x[0]=3,以此类推,for循环完毕x=[3,5,7,11,11]

demo
x := []int{123}
x, x[0] = nil, 456        // 此句不会发生恐慌
x, x[0] = []int{123}, 789 // 此句将产生恐慌

这个例子相对简单,不懂估值顺序知识可能也能明白,但是了解了赋值的估值顺序更加明白深层次的东西

注意

虽说有一些估值顺序规则,不过想强调的是仍然有很多不是白皮书中指定的规则,这取决于最终的编译器实现,比如:我们一直在讨论赋值表达式的左边,右边表达式的估值顺序是怎么样的呢?这并没有在白皮书中指定,这取决于具体的编译器实现

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值