2024年最新避免defer陷阱:拆解延迟语句,掌握正确使用方法,2024年最新Golang综合面试

img
img
img

既有适合小白学习的零基础资料,也有适合3年以上经验的小伙伴深入学习提升的进阶课程,涵盖了95%以上Go语言开发知识点,真正体系化!

由于文件比较多,这里只是将部分目录截图出来,全套包含大厂面经、学习笔记、源码讲义、实战项目、大纲路线、讲解视频,并且后续会持续更新

如果你需要这些资料,可以戳这里获取

  1. 资源释放:延迟语句可以用于在函数返回前释放打开的文件、关闭数据库连接、释放锁等资源,以确保资源的正确释放,避免资源泄漏。
  2. 错误处理:延迟语句可以用于处理函数执行过程中可能发生的错误。通过在函数开始时设置延迟语句,在函数返回前检查错误并进行相应的处理,可以简化错误处理的逻辑。
  3. 日志记录:延迟语句可以用于在函数返回前记录日志或执行其他的调试操作,以便在函数执行过程中收集相关的信息。

延迟语句的使用可以提高代码的可读性和可维护性,同时确保资源的释放和清理操作按照逆序进行。它是Go语言中一种常用的编程技巧,用于处理资源管理和错误处理等场景。

避坑之旅

实际开发中defer的使用并不像前面介绍的这么简单,defer用不好,会陷入泥潭。

下面我从两个角度带大家避坑:

  1. 首先拆解一下延迟语句的执行,注意Go语言的return语句不是原子性的;
  2. 另外重点和大家分享一下defer语句后面使用匿名函数和非匿名函数的区别。

拆解延迟语句

避免陷入泥潭的关键是必须深刻理解下面这条语句:

return xxx

上面这条语句经过编译之后,实际上生成了三条指令:

1)返回值 =xxx。

2)调用 defer 函数。

3)空的 return。

第1和第 3 步是return语句生成的指令,也就是说return并不是一条原子指令;

第2步是 defer 定义的语句,这里可能会操作返回值,从而影响最终结果。

下面来看两个例子,试着将return 语句和 defer语句拆解到正确的顺序。

第一个例子:
func f()(r int){
  t:=5

  defer func(){
    t=t+5
    }()
    
  return t
}

拆解后:

func f()(r int){
  t:=5
  
  //1,赋值指令
  r=t

  // 2.defer 被插入到赋值与返回之间执行,这个例子中返回值r没被修改过 
  func(){
    t=t+5
    }()
    
  //3.空的 return 指令
  return
  }

这里第二步实际上并没有操作返回值r,因此,main函数中调用f()得到5。

第二个例子:
func f()(r int){
  defer func(r int){
    r=r+5
    }(r)
    
    return 1
}

拆解后:

func f() (r int) {
  //1.赋值 
  r=1
  
  //2.这里改的r是之前传进去的r,不会改变要返回的那个r值 
  func(r int) {
    r=r+5
  }(r)
  
  // 3. 空的 return 
  return
}

第二步,改变的是传值进去的r,是形参的一个复制值,不会影响实参r。因此,main函数中需要调用f()得到1。

defer匿名函数

在Go语言中,使用匿名函数作为defer的参数时,可以理解为:defer语句中的匿名函数在包裹该defer语句的函数返回后才执行。这是因为defer语句的执行时机是在包裹函数即将返回之前,但在实际返回之前。

为什么不是在return语句之前执行呢?这是因为defer语句的设计初衷是为了在函数返回之前执行一些清理操作,例如关闭文件、释放资源等。将defer语句放在return语句之后,可以确保在函数返回之前执行这些清理操作,保证函数的执行完整性和资源的正确释放。

在使用匿名函数和非匿名函数作为defer的参数时,主要区别在于对函数参数的传递和作用域的影响:

  1. 匿名函数作为defer的参数:匿名函数可以直接在defer语句中定义,可以访问外部函数的变量,并且在执行时会使用当前的变量值。这种方式可以方便地在defer语句中使用外部变量,但需要注意变量的值在执行时可能已经发生了改变。
  2. 非匿名函数作为defer的参数:非匿名函数需要先定义好,然后作为defer的参数传递。在执行时,会使用函数的当前参数值。这种方式可以在defer语句中使用已定义的函数,但需要注意函数参数的传递和作用域。

产生这种区别的原因是,匿名函数和非匿名函数在定义和作用域上的差异。匿名函数可以直接在defer语句中定义,可以访问外部函数的变量,而非匿名函数需要先定义好,然后作为参数传递。这种设计灵活性使得开发者可以根据具体的需求选择合适的方式来使用defer语句。

举例来说

当使用匿名函数作为defer的参数时,可以在defer语句中直接定义匿名函数,并访问外部变量。

以下是一个示例代码:

img
img
img

既有适合小白学习的零基础资料,也有适合3年以上经验的小伙伴深入学习提升的进阶课程,涵盖了95%以上Go语言开发知识点,真正体系化!

由于文件比较多,这里只是将部分目录截图出来,全套包含大厂面经、学习笔记、源码讲义、实战项目、大纲路线、讲解视频,并且后续会持续更新

如果你需要这些资料,可以戳这里获取

适合3年以上经验的小伙伴深入学习提升的进阶课程,涵盖了95%以上Go语言开发知识点,真正体系化!**

由于文件比较多,这里只是将部分目录截图出来,全套包含大厂面经、学习笔记、源码讲义、实战项目、大纲路线、讲解视频,并且后续会持续更新

如果你需要这些资料,可以戳这里获取

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值