前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >Go语言中的defer

Go语言中的defer

原创
作者头像
似水流年o
发布2022-01-17 14:31:22
2990
发布2022-01-17 14:31:22
举报
文章被收录于专栏:编程学习收获编程学习收获

1.defer是什么?

defer是Golang中的一个关键字,用来修饰函数,被defer修饰的函数会被延时执行。

当一个函数调用前有关键字 defer时, 那么这个函数的执行会推迟到包含这个 defer 语句的函数

返回 / 结束 / 对应的goroutine发生panic的时候

2.defer的作用?

  • 创建资源后(比如打开文件,获取数据库连接,获取锁),可以立即执行defer file.Close()等关闭操作。这种方式相对于其他编程语言在代码最后执行Close()方法会更加简便。

3.defer的使用

  • 案例1
代码语言:javascript
复制
func main() {
	defer fmt.Printf("%v\n", "last")
	fmt.Printf("%v\n", "first")
	fmt.Printf("%v\n", "second")
}

first
second
last

总结:被defer关键字修饰的函数(Printf函数)执行时机会在包含这个 defer 语句的函数 (main函数)返回/结束时候执行。

  • 案例2
代码语言:javascript
复制
func main() {
	m := 1
	defer fmt.Printf("x=%v\n", m)
	m++
	fmt.Printf("y=%v\n", m)
}

y=2
x=1

代码语言:javascript
复制
func main() {
	m := 1
	defer func(m int) {
		fmt.Printf("x=%v\n", m)
	}(m)
	m++
	fmt.Printf("y=%v\n", m)
}
x=2
y=1

总结:通过defer修饰的函数,这个函数的参数值在defer的时候就被确定了。

但是defer函数内部所使用的变量值是外部函数运行结束后的值。如下案例3

案例3:

代码语言:javascript
复制
func main() {
	m := 1
	defer func() {
		fmt.Printf("x=%v\n", m)
	}()
	m++
	fmt.Printf("y=%v\n", m)
}

y=2
x=2

案例4:

代码语言:javascript
复制
func main() {
   m := 1
   defer fmt.Printf("x=%v\n", m)
   defer fmt.Printf("y=%v\n", m)
   fmt.Printf("z=%v\n", m)
}
z=1
y=1
x=1

总结:defer关键字声明的函数执行顺序遵循栈结构后进先出)。

通俗解释defer声明的函数会依次压入到栈中,在它的外部函数执行结束后,开始弹栈,所以y=1会比x=1先打印

4.defer和return的执行顺序 (重点)

案例5:

代码语言:javascript
复制
func main() {  
	fmt.Printf("z=%v\n", test())
}

func test() int { //无名返回值
	i := 0
	defer func() {
		i++
	}()
	return i  //z=0
}

案例6:

代码语言:javascript
复制
func main() {
	fmt.Printf("z=%v\n", test())
}

func test() (i int) { //有名返回值
	defer func() {
		i++
	}()
	return i  //z=1
}

通过上面两个例子,我们可以看到:被调用函数返回值声明为int(i int) ,两者的返回值是不一样的

解决这个疑惑,我们需要知道:return非原子操作,包括赋值返回值两步。而deferreturn的执行顺序是:return执行第一步,把结果写入返回值中(赋值);然后执行defer定义的函数内容;最后return执行第二步进行数值返回操作(返回值)。

解释实例5:

  1. 赋值。因为函数返回值没有命名,所以return时会默认指定一个返回值(假设为j),将i赋值给j,即i=j=0;
  2. defer函数处理defer操作会对i进行+1,但这个操作与j无关,所以j依旧为0;
  3. 返回值。返回j = 0;

解释实例6:

  1. 赋值。因为函数返回值已经被命名,return会返回(i int)定义中的i变量;
  2. defer函数处理。defer操作会对i进行+1;
  3. 返回值。返回i = 1;

总结:出现案例5案例6返回值不同的原因是Golang底层对函数无名返回值有名返回值的处理机制是不一样的

原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。

如有侵权,请联系 cloudcommunity@tencent.com 删除。

原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。

如有侵权,请联系 cloudcommunity@tencent.com 删除。

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档