Go 语言编程 — defer 关键字
【摘要】 目录
文章目录
目录defer 关键字defer 的用途之一:释放资源defer 的用途之二:执行 recover(恢复)defer 特性多个 defer 的执行顺序被 deferred 函数的参数在 defer 时确定被 defer 的函数可以读取和修改带名称的返回值
defer 关键字
go 用 defer(推迟)关键字来延迟执行指定的函数,比...
目录
defer 关键字
go 用 defer(推迟)关键字来延迟执行指定的函数,比如:
func a() int {
defer b()
return 0
}
函数 b() 发生在 return 0 之后。
defer 是一个面向编译器的声明,会让编译器做两件事:
- 编译器会将 defer 声明编译为
runtime.deferproc(fn)
,这样运行时,会调用runtime.deferproc
,在 deferproc 中将所有 defer 挂到 Goroutine 的 defer 链上; - 编译器会在函数 return 之前,增加 runtime.deferreturn 调用,开始处理前面挂在 defer 链上的所有 defer。
可见,defer 关键字会将指定的函数延迟到函数 return 语句之后执行,包括 Goroutine 的 return。defer 常用来释放数据库连接、文件打开句柄等资源的操作,有类似于 Python with Context 的作用。
defer 的用途之一:释放资源
由于 defer 的延迟特性,defer 常用在函数调用结束之后用于清理相关的资源,比如:
f, _ := os.Open(filename)
defer f.Close()
文件资源的释放会在函数调用结束之后借助 defer 语句自动执行,打开和释放必须相对应。
示例:
func CopyFile(dstName, srcName string) (written int64, err error) { src, err := os.Open(srcName) if err != nil { return } defer src.Close() dst, err := os.Create(dstName) if err != nil { return } defer dst.Close() return io.Copy(dst, src)
}
defer 的用途之二:执行 recover(恢复)
被 defer 的函数在 return 之后执行,这个时机点正好可以捕获函数抛出的 panic,因而 defer 的另一个重要用途就是执行 recover。
recover 只有在 defer 中使用才更有意义,如果在其他地方使用,由于程序已经调用结束并提前返回而无法有效捕捉错误。
package main
import ( "fmt"
)
func main() { defer func() { if ok := recover(); ok != nil { fmt.Println("recover") } }() panic("error")
}
注意:defer 要放在 panic 执行之前。
defer 特性
多个 defer 的执行顺序
defer 的本质就是把关键字之后的函数执行压入一个栈(Stack)中延迟执行,所以当具有多个 defer 时,其执行顺序是后进先出(LIFO
)的。
defer func() { fmt.Println("1") }()
defer func() { fmt.Println("2") }()
defer func() { fmt.Println("3") }()
输出顺序是 3、2、1。
被 deferred 函数的参数在 defer 时确定
这是 defer 关键字的特点,一个函数被 defer 时,它的参数就已经确定了,即使 defer 之后参数发生了修改,也不会影响到 defer 时确定的数值。
func a() { i := 0 defer fmt.Println(i) i++ return
}
函数 a() 执行输出的是 0 而不是 1,因为 defer 时 i 的值是 0。
被 defer 的函数可以读取和修改带名称的返回值
被 defer 的函数是在 return 之后执行,可以修改带名称的返回值,例如下述示例中的返回值 i,在 defer 的 c() 中被修改了,所以返回的是 2。
func c() (i int) { defer func() { i++ }() return 1
}
文章来源: is-cloud.blog.csdn.net,作者:范桂飓,版权归原作者所有,如需转载,请联系作者。
原文链接:is-cloud.blog.csdn.net/article/details/107449051
【版权声明】本文为华为云社区用户转载文章,如果您发现本社区中有涉嫌抄袭的内容,欢迎发送邮件进行举报,并提供相关证据,一经查实,本社区将立刻删除涉嫌侵权内容,举报邮箱:
cloudbbs@huaweicloud.com
- 点赞
- 收藏
- 关注作者
作者其他文章
评论(0)