defer
语句的主要用途是在执行函数返回之前延迟执行一些操作。这些操作可能包括资源的释放
、文件的关闭
、解锁操作
等。defer
语句可以确保无论函数如何返回(包括发生panic
的情况),这些操作都会被执行,从而帮助确保代码的健壮性和可靠性。
defer
主要具有两大特性:
在当前函数执行完成后再调用defer
后的语句执行。
package main
import "fmt"
func main() {
defer fmt.Println("first defer")
fmt.Println("main kernel processing...")
}
输出结果:
$ go run main.go
main kernel processing...
first defer
当有多个defer语句时,遵循后进先出的原则来执行。
package main
import "fmt"
func main() {
defer fmt.Println("1. first defer.")
defer fmt.Println("2. second defer.")
defer fmt.Println("3. third defer.")
fmt.Println("main kernel processing...")
}
输出结果:
$ go run main.go
main kernel processing...
3. third defer.
2. second defer.
1. first defer.
在Go语言的函数中return
语句在底层并不是原子操作,它分为给返回值赋值
和RET指令
两步。而defer
语句执行的时机就在返回值赋值操作后,RET指令执行前。
package main
import "fmt"
func f1() int {
x := 5
defer func() {
x++
}()
return x //返回值=x -> new(int) = x(此时进行值传递 new(int)会获得x的一个副本) ; 执行defer -> x++(只影响了局部变量x) ; 执行RET
}
func f2() (x int) {
defer func() {
x++
}()
return 5 // 返回值=x -> x = x ; 执行defer -> x++ ; 执行RET
}
func f3() (y int) {
x := 5
defer func() {
x++
}()
return x // 返回值=x -> y = x(此时进行值传递 y会获得x的一个副本); 执行defer -> x++(只影响了局部变量x) ; 执行RET
}
func f4() (x int) {
defer func(x int) {
x++
}(x)
return 5 // 返回值=5 ; 执行defer -> 接收一个变量x并执行x++(此时接收一个值传递,x++只影响当前局部变量); 执行RET
}
func main() {
fmt.Println(f1())
fmt.Println(f2())
fmt.Println(f3())
fmt.Println(f4())
}
输出结果:
$ go run main.go
5
6
5
5
在defer
声明的时候,需要连同函数地址、函数形参一同压进栈内。所以当参数有需要调用其他函数计算结果的时候,需要先计算出结果后再压进栈。
package main
import "fmt"
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
}
输出结果:
$ go run main.go
A 1 2 3
B 10 2 12
BB 10 12 22
AA 1 3 4
解析:
首先声明并赋值两个变量x和y,分别是1和2
然后注册第一个defer语句的时候,Go需要确定每个函数的变量的值。因此要先调用一次calc
函数计算出值,并把这个defer语句压进栈内。此时会输出:
A 1 2 3
重新给变量x赋值,然后注册第二defer语句的时候,仍然需要确定每个函数的变量的值。再调用calc
函数计算出值,并把这个defer语句压进栈内。此时会输出:
B 10 2 12
重新给变量y赋值为20。然后从栈中取出最近压进去的defer语句并执行,此时会输出:
BB 10 12 22
然后再从栈中取出最近压进去的defer语句并执行,此时会输出:
AA 1 3 4
栈内没有defer语句后,执行RET。
package main
import "fmt"
func main() {
defer fmt.Println("defer 1")
defer fmt.Println("defer 2")
defer fmt.Println("defer 3")
panic("出错啦")
}
输出结果:
$ go run main.go
defer 3
defer 2
defer 1
panic: 出错啦
无论函数是正常返回还是通过panic
返回,defer
语句都会执行
基于Nginx+Supervisord+uWSGI+Django1.11.1+Python3.6.5构建