我刚刚开始学习golang,我对golang博客帖子here中使用defer更改命名返回值的一个例子感到困惑。
例子说:
- 延迟函数可以读取并分配给返回函数的命名返回值。
醇>在此示例中,延迟函数在周围函数返回后递增返回值i。因此,此函数返回2 :
func c() (i int) {
defer func() { i++ }()
return 1
}
但正如我从A Tour of Go - Named return values
所学到的不带参数的return语句返回指定的返回值。这被称为“裸体”回归。
我在下面的代码和函数b中进行了测试,它返回1,因为它不是上面提到的没有参数的返回语句。
func a() (i int) { // return 2
i = 2
return
}
func b() (i int) { // return 1
i = 2
return 1
}
所以我的问题是在第一个例子中,周围的函数c有一个命名的返回值i,但函数c使用 return 1 ,在第二个例子中我们可以看到它应该返回1不管我是什么价值。但是为什么在我更改延迟函数后,c函数返回i的值而不是值1?
在我输入问题时,我可能已经猜到了答案。是因为
return 1
等于
i = 1
return
在具有命名返回值变量i的函数中?
请帮我确认一下,谢谢!
答案 0 :(得分:30)
defer语句将函数调用推送到列表中。在周围函数返回后执行已保存调用的列表。 - The Go Blog: Defer, Panic, and Recover
了解上述陈述的另一种方法:
延迟语句将函数调用推送到堆栈。在周围函数返回之前,会立即调用已保存的调用弹出(LIFO)和延迟函数的堆栈。
func c() (i int) {
defer func() { i++ }()
return 1
}
返回1后,延迟func() { i++ }()
被执行。因此,按执行顺序:
为了理解:
func c() (i int) {
defer func() { fmt.Println("third") }()
defer func() { fmt.Println("second") }()
defer func() { fmt.Println("first") }()
return 1
}
执行令:
答案 1 :(得分:5)
我认为混淆是关于功能的功能如果你这样分类怎么样:
func main() {
fmt.Println(c()) //the result is 5
}
// the c function returned value is named j
func c() (j int) {
defer changei(&j)
return 6
}
func changei(j *int) {
//now j is 6 because it was assigned by return statement
// and if i change guess what?! i changed the returned value
*j--;
}
但如果返回值的名称不是这样的:
func main() {
fmt.Println(c()) //the result will become 6
}
// the c function returned value is not named at this time
func c() int {
j := 1
defer changei(&j)
return 6
}
func changei(j *int) {
//now j = 1
// and if i change guess what?! it will not effects the returned value
*j--;
}
我希望这会清除混乱,这就是我如何快乐的Go编码
答案 2 :(得分:4)
根据Go规范:
Return Statements 指定结果的“return”语句在执行任何延迟函数之前设置结果参数。
Defer Statements “...在周围函数返回之前立即调用延迟函数......”
所以是的,正如您所假设的那样,指定了返回变量,然后延迟语句递增它。
我想补充说,命名的返回参数会导致细微的错误,除非别无选择,否则通常应该避免。