```go
package main
import (
"fmt"
)
func main() {
fmt.Println("a return:", a()) // 打印结果为 a return: 0
}
func a() int {
var i int
defer func() {
i++
fmt.Println("a defer2:", i) // 打印结果为 a defer2: 2
}()
defer func() {
i++
fmt.Println("a defer1:", i) // 打印结果为 a defer1: 1
}()
return i
}
```
```go
package main
import (
"fmt"
)
func main() {
fmt.Println("b return:", b()) // 打印结果为 b return: 2
}
func b() (i int) {
defer func() {
i++
fmt.Println("b defer2:", i) // 打印结果为 b defer2: 2
}()
defer func() {
i++
fmt.Println("b defer1:", i) // 打印结果为 b defer1: 1
}()
return i // 或者直接 return 效果相同
}
```
**对于上面这两不同的返回值,defer的行为有点不是很理解,defer到底是在return前执行,还是retrun后执行?**
1、a函数的定义中,定义了int类型的返回值(匿名,假设为 '-' );并在函数内部定义int类型的函数局部变量 i ;在a函数开始调用时,栈空间内首先被分配了返回值 - 的栈地址,函数a执行到 return i 时,栈空间中的局部变量 i 被赋值给返回值 - (此时变量i为0),之后执行defer调用的函数时仅仅改变了变量 i 的值而不会影响返回值 - 。
2、b函数的定义中,同样定义了int类型的返回值但给定了具体的命名。也就是说b函数中的变量 i 即为栈空间内分配的返回值变量,在执行到return i 时不需要做返回值赋值。所以执行defer调用的函数时改变变量 i 的值就是在改变返回值。
#2
更多评论
一个是匿名返回 一个是具名返回,
两者都是返回值入栈后才执行defer
区别在于前者defer使用的是自己复制的栈变量进行运算所以返回值是0
后者是defer使用具名的变量没有复制进行运算, 所以最后返回值被修改为2.
个人理解,期待大神的权威解答.
#1
那么简化成一句话总结一下, 匿名调用返回值和内部的i是两个栈变量地址, 具名调用返回值和i是同一个栈变量地址? over.
我上面的解释其实也是这个意思, 只不过用复制运算可能更容易理解一些?
#3