表达式估值
当估值一个表达式、赋值语句或者函数返回语句中的操作数时,所有的函数调用、方法调用和通道操作将按照它们在代码中的出现顺序进行估值。但是 Go 白皮书未指定表达式中其它估值顺序。
目前 Go 的编译器官方维护有两种主流的,一个是 gc 编译器,一个是 gccgo 编译器,两种编译器打印出来的值不一样。
package main
var x, i = []int{1, 2}, 0
func f() int {i = 1; return 9}
func main() {
x[i] = f()
println(x[0], x[1])
}
// gc 编译器将打印出:1 9
// gccgo 编译器将打印出:9 2
一种说法是先估值函数 f,然后在估值 i,这样的结果就是 1,9
另一种说法是先估值变量 i,然后再估值函数 f,这样结果为 9,2
打印出 1 9 或者 9 2 都不违反 Go 语言白皮书。因为表达式 f() 和 i 之间的相对估值顺序未定义。
package main
import "fmt"
func f(p *int) int {
*p = 123
return *p
}
func g(x int) (a, b int) {
return x, f(&x)
// <=> a, b = x, f(&x);
// return
}
func main() {
fmt.Println(g(0))
}
// gc 编译器将打印出:123 123
// gccgo 编译器将打印出:0 123
同样,因为编译器的估值顺序不同,造成了两种不同的输出结果
编译器在估值 x 和 f 函数的时候,先估值 x,就会造成输出 0 123
如果先估值 f 函数,就会输出 123 123
package main
var _ = f("w", x)
var x = f("x", z)
var y = f("y", x)
var z = f("z")
func f(s string, deps ...int) int {
print(s)
return 0
}
func main() {}
// 将打印出 zxwy
全局变量的初始化顺序,首先初始化不依赖于其他全局变量的变量
每次初始化一个变量后就需要重新开始新的一轮初始化