Golang程序执行流程深度解析
Golang程序执行流程深度解析
func main() {
i, j := 10, 10
var sum1, sum2 int
sum1 = (i / 2) + think(&i)
sum2 = think(&j) + (i / 2)
fmt.Printf(“Value of sum1 is %d and sum2 is %d”, sum1, sum2)
}
func think(k *int) int {
*k += 4
return 3*(*k) - 1
}
这个简短程序的输出是 sum1=sum2=48。Go 是如何进行求值的?
2 回复
你好,欢迎!Go 语言是急切求值且静态的,但并非一个真正确定性的编程语言。所以结果是 48 和 48,因为 think(&1) 在 (i/2) 之前执行,或者更准确地说:sum1 = (7) + 41。对于 sum2 情况相同。Go 并不强制规定求和表达式中左右操作数的求值顺序。这种行为似乎容易出错,但会极大地促使你编写更清晰的代码,分解复杂的语句和表达式。
更多信息请参阅此链接。
func main() {
fmt.Println("hello world")
}
更多关于Golang程序执行流程深度解析的实战系列教程也可以访问 https://www.itying.com/category-94-b0.html
在Go语言中,函数参数和表达式的求值顺序是未定义的,但操作数的求值顺序是从左到右。不过对于同一个表达式中的多个函数调用,Go并没有规定它们的求值顺序。让我们分析这个具体案例:
package main
import "fmt"
func main() {
i, j := 10, 10
var sum1, sum2 int
// 关键在这里:表达式求值顺序
sum1 = (i / 2) + think(&i) // 情况1
sum2 = think(&j) + (j / 2) // 情况2(注意:应该是j/2,不是i/2)
fmt.Printf("Value of sum1 is %d and sum2 is %d", sum1, sum2)
}
func think(k *int) int {
*k += 4
return 3*(*k) - 1
}
实际上,原代码有个笔误,应该是:
sum2 = think(&j) + (j / 2) // 不是 (i / 2)
执行流程分析:
对于sum1的计算:
(i / 2)先求值:10 / 2 = 5think(&i)后求值:*k += 4→i = 10 + 4 = 14return 3*14 - 1 = 42 - 1 = 41
sum1 = 5 + 41 = 46
对于sum2的计算:
think(&j)先求值:*k += 4→j = 10 + 4 = 14return 3*14 - 1 = 42 - 1 = 41
(j / 2)后求值:14 / 2 = 7sum2 = 41 + 7 = 48
但实际输出是sum1=sum2=48,这说明:
在Go的当前实现中,对于表达式 (i / 2) + think(&i):
- 操作数从左到右求值,所以
(i / 2)先计算 - 但函数调用
think(&i)中的副作用(修改i的值)不会影响已经计算过的(i / 2)
然而,如果原代码确实是 think(&j) + (i / 2),那么:
think(&j)修改的是j,不影响i(i / 2)中的i仍然是10- 结果应该是
41 + 5 = 46
要得到sum1=48,需要:
sum1 = (i / 2) + think(&i) // 假设think(&i)先执行
// think(&i)先执行:i变为14,返回41
// 然后(i/2):14/2=7
// 结果:7+41=48
关键点:
- Go不保证二元操作符两边的求值顺序
- 但保证操作数自身的求值顺序
- 实际编译器中,通常从左到右求值
验证示例:
package main
import "fmt"
func main() {
// 演示求值顺序
x := 10
result := f(&x) + g(&x)
fmt.Printf("Result: %d, x: %d\n", result, x)
}
func f(p *int) int {
*p += 5
fmt.Printf("f called, *p=%d\n", *p)
return *p
}
func g(p *int) int {
*p *= 2
fmt.Printf("g called, *p=%d\n", *p)
return *p
}
// 输出顺序可能不同,结果也不同
结论: 原程序输出sum1=sum2=48表明在当前Go实现中:
- 对于
sum1:think(&i)在(i / 2)之前执行 - 对于
sum2:think(&j)在(j / 2)之前执行 - 但这是编译器实现细节,不是语言规范保证的
编写Go代码时,不应依赖这种未定义的求值顺序,有副作用的表达式应该分开写:
// 明确的顺序
temp1 := think(&i)
sum1 = (i / 2) + temp1
// 或者
temp2 := think(&j)
sum2 = (j / 2) + temp2

