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

Go defer 使用

作者头像
王小明_HIT
发布2021-05-20 10:39:36
3390
发布2021-05-20 10:39:36
举报
文章被收录于专栏:程序员奇点程序员奇点

defer特性:

  1. 关键字 defer 用于注册延迟调用。
  2. 这些调用直到 return 前才被执。因此,可以用来做资源清理。
  3. 多个defer语句,按先进后出的方式执行。
  4. defer语句中的变量,在defer声明时就决定了。
defer用途:
  1. 关闭文件句柄
  2. 锁资源释放
  3. 数据库连接释放
代码语言:javascript
复制
package main

import "fmt"

func main() {
    var users [5]struct{}
    for i := range users {
        defer fmt.Println(i)
    }
}

输出:4 3 2 1 0 ,defer 是先进后出

代码语言:javascript
复制
package defer_test

import (
 "fmt"
 "testing"
)

func TestDefer1(t * testing.T) {
 var users [5]struct{}
 for i := range users {
  defer func() { fmt.Println(i) }()
 }
}

输出结果:4 4 4 4 4 是否在想一个问题,输出结果不是 4 3 2 1 0 , 由于是闭包用到的变量 i 在执行的时候已经变成了4 , 所以输出全部是 4, 如何正常输出。4 3 2 1 0 ?不用闭包,换成函数即可。

代码语言:javascript
复制
func TestDefer2(t *testing.T) {
 var users [5]struct{}
 for i := range users {
  defer Print(i)
 }
}

func Print(i int) {
 fmt.Println(i)
}

函数的输出结果是 :4 3 2 1 0

再看个结构体的例子

代码语言:javascript
复制
func (t *Users) GetName(){
 fmt.Println(t.name)
}

func TestDefer3(t * testing.T){
  list := []Users{{"乔峰"}, {"慕容复"},{"欧阳克"}}
  for _, t := range list {
   defer t.GetName()
  }
}

发现没,输出的结果竟然是 欧阳克 欧阳克 欧阳克

不是欧阳克 慕容复 乔峰

如何要输出 :欧阳克 慕容复 乔峰

写个函数:

代码语言:javascript
复制
type Users struct {
 name string
}


func (t *Users) GetName(){
 fmt.Println(t.name)
}

func GetName(t Users){
 t.GetName()
}

func TestDefer4(t *testing.T) {
 list := []Users{{"乔峰"}, {"慕容复"},{"欧阳克"}}
 for _, t := range list {
  defer GetName(t)
 }
}

函数输出结果:欧阳克 慕容复 乔峰

如果不想多写一个函数,输出 欧阳克 慕容复 乔峰

要怎么搞?复制一份即可

代码语言:javascript
复制
type Users struct {
 name string
}

func (t *Users) GetName() {
 fmt.Println(t.name)
}

func TestDefer5(t *testing.T) {
 list := []Users{{"乔峰"}, {"慕容复"}, {"欧阳克"}}
 for _, t := range list {
  t1 := t
  defer t1.GetName()
 }
}

输出结果:欧阳克 慕容复 乔峰

defer 后面的语句在执行的时候,函数调用的参数会保存起来,复制一份,但是不执行。

多个 defer 注册,采用的是 FILO 先进后出的方式,哪怕函数发生错误, 这些调用依然会被执行。

代码语言:javascript
复制
func users(i int) {
 defer println("北丐")
 defer println("南帝")

 defer func() {
  println("西毒")
  println(10 / i) // 异常未被捕获,逐步往外传递,最终终止进程。
 }()

 defer println("东邪")
}
func TestDefer6(t *testing.T) {
 users(0)
 println("武林高手排行榜,这里不会被输出")
}

defer 与 return

在有命名返回值的函数中, 执行 return "风清扬"的时候实际上已经将 s 的值重新赋值为 风清扬

代码语言:javascript
复制
func Users2() (s string) {
   s = "乔峰"
   defer func() {
    fmt.Println("延迟执行后:" + s)
   }()

   return "清风扬"
}

func TestDefer7(t *testing.T) {
   Users2() // 输出:延迟执行后:清风扬
}

输出结果:

代码语言:javascript
复制
延迟执行后:清风扬
--- PASS: TestDefer7 (0.00s)
PASS

微信号:程序员开发者社区

博客:CSDN 王小明

关注我们,了解更多

参考资料
  • https://www.cnblogs.com/phpper/p/11984161.html
  • https://draveness.me/golang/docs/part2-foundation/ch05-keyword/golang-defer/
本文参与 腾讯云自媒体分享计划,分享自微信公众号。
原始发表:2021-05-06,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 程序员奇点 微信公众号,前往查看

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

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • defer特性:
    • defer用途:
      • 参考资料
  • defer 与 return
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档