春雪满空来,触处似花开。——赵嘏《喜张沨及第》
结论
- 多个defer的执行顺序为
先进后出
- 匿名返回值是在
return
执行时被声明,有名返回值则是在函数声明的同时被声明,因此在defer
语句中只能访问有名返回值,而不能直接访问匿名返回值 return
其实应该包含前后两个步骤:第一步是给返回值赋值(若为有名返回值则直接赋值,若为匿名返回值则先声明再赋值);第二步是调用RET
返回指令并传入返回值,而RET
则会检查defer
是否存在,若存在就先逆序插播defer语句,最后RET携带返回值退出函数- 延迟函数的参数在 defer 语句出现时就已经确定下来了(defer声明时会先计算确定参数的值,defer推迟执行的仅是其函数体)
解释
结论1
package main
func main() {
for i := 0; i < 4; i++ {
defer fmt.Print(i)
}
// Output:
// 3
// 2
// 1
// 0
}
结论2和结论3
package main
import (
"fmt"
)
func main() {
fmt.Println(a())
// Output:
// 1
// 2
}
// 无名返回值
func a() int {
defer func() { i++ }()
return 1
}
// 有名返回值
func a() (i int) {
defer func() { i++ }()
return 1
}
结论4
package main
import (
"fmt"
)
func main() {
a()
b()
// Output:
// 0
// enter: b
// in b
// leave: b
}
func a() {
i := 0
defer fmt.Println(i) // 调用时i已经确定为0
i++
return
}
func trace(s string) s {
fmt.Println("enter: ", s)
return s
}
func un(s) {
fmt.Println("leave: ", s)
}
func b() {
defer un(trace("b")) // defer声明时会先计算确定参数的值,即执行了trace(),defer推迟执行的仅是其函数体un()
fmt.Println("in b")
}