defer
Go语言中的defer
语句会将其后面跟随的语句进行延迟处理。在defer
归属的函数即将返回时,将延迟处理的语句按defer
定义的逆序进行执行,也就是说,先被defer
的语句最后被执行,最后被defer
的语句,最先被执行。
举个例子:
func main() {
fmt.Println("start")
defer fmt.Println(1)
defer fmt.Println(2)
defer fmt.Println(3)
fmt.Println("end")
}
输出结果:
start
end
3
2
1
由于defer
语句延迟调用的特性,所以defer
语句能非常方便的处理资源释放问题。比如:资源清理、文件关闭、解锁及记录时间等。
defer执行时机
在Go语言的函数中return
语句在底层并不是原子操作,它分为给返回值赋值和RET指令两步。而defer
语句执行的时机就在返回值赋值操作后,RET指令执行前。具体如下图所示:
func f1() int {
x := 5
defer func() {
x++
}()
return x //1 ,返回值赋值=5 2,defer x++ 不改变返回值3,ret指令
}
func f2() (x int) {
defer func() {
x++
}()
return 5
}
func f3() (y int) {
x := 5
defer func() {
x++
}()
return x
}
func f4() (x int) {
defer func(x int) {
x++
}(x) //改变的是副本
return 5
}
func f5() (x int) {
defer func(x *int) {
*x++
}(&x) //改变的是副本
return 5
}
func main() {
fmt.Println(f1()) //5
fmt.Println(f2()) //6
fmt.Println(f3()) //5
fmt.Println(f4()) //6
fmt.Println(f5()) //6
}
defer面试题
func calc(index string, a, b int) int {
ret := a + b
fmt.Println(index, a, b, ret)
return ret
}
func main() {
x := 1
y := 2
defer calc("AA", x, calc("A", x, y))
x = 10
defer calc("BB", x, calc("B", x, y))
y = 20
}
分析过程:
//x := 1
//y := 2
//calc("A", x, y) calc("A", 1,2) -> "A" 1 2 3
//x = 10
//calc("B", x, y) calc("B",10,2) -> "B" 10 2 12
//y = 20
//defer calc("BB", x, calc("B", x, y)) calc("BB",10,12) -> "BB" 10 12 22
//defer calc("AA", x, calc("A", x, y)) calc("AA",1,3) -> "AA" 1 3 4```