(1)defer 关键字,可以用来注册多个延迟调用,这些调用以先进后出(FILO)的顺序 在函数返回前被执行。常用于保证一些资源最终一定能够得到回收和释放。
(2)关于defer的使用,主要注意以下几点:
- defer后面必须是函数或方法的调用,不能是语句,否则会报 expression in defer must be function call 的错误。
![]()
- defer函数的实参在注册时通过值拷贝传递。
func main() {
f()
//输出 defer i= 0
}
func f() int {
v := 0
//值拷贝
defer func(i int) {
println("defer i=", i)
}(v)
v++
return v
}
- defer语句必须先注册后才能执行,如果defer位于return之后,则 defer 没有注册,不会执行。
func main() {
//先进后出
defer func() {
println("first")
}()
defer func() {
println("second")
}()
println(" main body ")
p := 1
println("p=", p)
//return语句返回
return
defer func() {
println(" third ") //之前有return 不会输出
}()
}
//output:
// main body
// p=1
//second
//first
- 主动调用os.Exit(int)退出进程时,defer将不再被执行,此种情况,是有条件的 :
- os.Exit(int)方法之前无return语句
- os.Exit(int)方法调用之前如果调用了子函数且子函数中有defer语句,则子函数中的defer语句也会被执行。
func main() {
f()
defer func() {
println("my defer ")
}()
println("func body")
//return
os.Exit(1)
//output:
//defer i= 0
//func body
}
func f() int {
v := 0
//值拷贝
defer func(i int) {
println("defer i=", i)
}(v)
v++
return v
}
- defer语句的位置不当,也会引起panic,一般defer语句放于错误检查语句之后。
- 因defer会推迟资源的释放,defer尽量不要放于循环语句中。
- defer 中 最好不要对有名返回值参数进行操作,否则会引起莫名其妙的结果。
func main() {
f()
loop()
//先进后出
defer func() {
println("first")
}()
defer func() {
println("second")
}()
println(" main body ")
p := 1
println("p=", p)
//return 之前 主动调用os.Exit(int),如果之前有调用子函数,子函数的defer语句还会执行。
os.Exit(1)
//return语句返回
return
defer func() {
println(" third ") //之前有return 不会输出
}()
}
//output:
//defer i= 0
//loop= 4
//loop= 3
//loop= 2
//loop= 1
//loop= 0
//main body
//p= 1
func f() int {
v := 0
//值拷贝
defer func(i int) {
println("defer i=", i)
}(v)
v++
return v
}
//测试放于循环语句中的输出
func loop() {
for i := 0; i < 5; i++ {
defer println("loop=", i)
}
}
本文深入探讨了Go语言中defer关键字的使用方法及其注意事项。详细解释了defer如何实现资源的回收和释放,并通过示例展示了其先进后出的执行顺序。此外,还特别提到了在不同场景下defer的行为差异。
607

被折叠的 条评论
为什么被折叠?



