1.规则
- 延迟函数的参数在defer语句出现时已经确定
func a(){
i := 0
defer fmt.Println(i) // 函数输出0
i++
return
}
函数参数值在defer出现时就已经确定了下来 即拷贝了一份 后续对i的修改不会影响原始延迟函数中的执行 输出0
延迟函数执行按后进先出顺序执行 即先出现的defer最后执行
根据goroutine可以对此进行理解-
延迟函数可能操作主函数的具名返回值
- 首先 Go语言中允许在表明返回类型时可以顺便给返回值定义名字
func a(b int) // 定义返回名b
此时b为具名返回值
- 其次 我们需要直到return在汇编执行中并不是原子操作 它需要分为两步运行
func a(b int){
i := 1
return i
}
# 分步
b = i
return (此时return的值是b 也即是说在返回前需要将i的值赋给真正的返回值b
而延迟函数的执行正好在return之前
即
b = i
defer语句
return
看一个例子
func a(b int){
i := 1
defer func(){
b++
}()
return i
}
此时执行顺序是
b = i
b++
return b
对于返回字面值来说 defer语句无法操作其返回值
对于返回匿名变量来说 defer操作该返回值的前提是延迟函数参数中传入的是匿名变量的地址 才有可能操作返回值
func foo() int {
var i int
defer func() {
i++
}()
return i
}
此时操作的返回值并不是i 假定return有一个变量来存储真正的返回值 则步骤如下
a = i // a是真正的返回值
i++
return a
这样的defer延迟函数对函数返回值不受影响