defer
defer简介
在Go语言中,可以使用关键字defer向函数注册退出调用,即主函数退出时,defer后的函数才被调用。defer语句的作用是不管程序是否出现异常,均在函数退出时自动执行相关代码。
多个defer函数按照先进后出的顺序执行。
defer特点
- 参数的实时解析
func test() {
i := 0
defer fmt.Println(i) //输出0,因为i此时就是0
i++
defer fmt.Println(i) //输出1,因为i此时就是1
return
}
// Output:
// 1
// 0
- 先进后出的执行顺序
func b() {
for i := 0; i < 4; i++ {
defer fmt.Print(i)
}
}
// Output:
// 3210
- 读取有名返回值
func c() (i int) {
defer func() { i++ }()
return 1
}
// Output:
// 2
defer的最佳实践
f.Close() 可能会返回一个错误,可这个错误会被我们忽略掉。在defer中关闭资源,同样要考虑错误的处理。
func do() error {
f, err := os.Open("book.txt")
if err != nil {
return err
}
defer func() {
if err := f.Close(); err != nil {
// 处理错误
}
}()
// ..code...
return nil
}
defer的错误案例
- 释放同一资源
func do() error {
f, err := os.Open("book.txt")
if err != nil {
return err
}
defer func() {
if err := f.Close(); err != nil {
// log etc
}
}()
// ..code...
f, err = os.Open("another-book.txt")
if err != nil {
return err
}
defer func() {
if err := f.Close(); err != nil {
// log etc
}
}()
return nil
}
// Outout:
// closing resource #another-book.txt
// closing resource #another-book.txt
defer很适合在资源释放的场景使用,但是要注意,defer是有不小的性能损耗,且过度使用后也会导致逻辑变复杂。