Go 语言编程 — defer 关键字

举报
云物互联 发表于 2021/08/06 01:22:06 2021/08/06
1.8k+ 0 0
【摘要】 目录 文章目录 目录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 是一个面向编译器的声明,会让编译器做两件事:

  1. 编译器会将 defer 声明编译为 runtime.deferproc(fn),这样运行时,会调用 runtime.deferproc,在 deferproc 中将所有 defer 挂到 Goroutine 的 defer 链上;
  2. 编译器会在函数 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

抱歉,系统识别当前为高风险访问,暂不支持该操作

    全部回复

    上滑加载中

    设置昵称

    在此一键设置昵称,即可参与社区互动!

    *长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。

    *长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。