Go defer 使用

简介: Go defer 使用

defer特性:


  1. 关键字 defer 用于注册延迟调用。
  2. 这些调用直到 return 前才被执。因此,可以用来做资源清理。
  3. 多个defer语句,按先进后出的方式执行。
  4. defer语句中的变量,在defer声明时就决定了。

defer用途:


  1. 关闭文件句柄
  2. 锁资源释放
  3. 数据库连接释放

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


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


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 ?不用闭包,换成函数即可。


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

再看个结构体的例子


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


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

不是欧阳克 慕容复 乔峰

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

写个函数:


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)
 }
}


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

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

要怎么搞?复制一份即可


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 先进后出的方式,哪怕函数发生错误, 这些调用依然会被执行。


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 的值重新赋值为 风清扬

func Users2() (s string) {
   s = "乔峰"
   defer func() {
    fmt.Println("延迟执行后:" + s)
   }()
   return "清风扬"
}
func TestDefer7(t *testing.T) {
   Users2() // 输出:延迟执行后:清风扬
}


输出结果:


延迟执行后:清风扬
--- PASS: TestDefer7 (0.00s)
PASS
相关文章
|
6月前
|
Go
Go语言中defer的执行顺序详解
【2月更文挑战第22天】
103 4
|
Cloud Native Go
GO 中的 defer 有哪些注意事项?上
GO 中的 defer 有哪些注意事项?上
|
Go
Go语言编程的一大杀器!详解defer语句
Go语言编程的一大杀器!详解defer语句
67 0
|
3月前
|
存储 Go
掌握 Go 语言的 defer 关键字
掌握 Go 语言的 defer 关键字
|
3月前
|
Go
实验深度理解Go中try...catch...的panic、defer、recover用法
文章通过实验代码演示了Go语言中如何使用panic、defer和recover函数来模拟try...catch...的异常处理机制,并详细解释了每个函数的作用和在异常处理中的使用场景。
35 0
|
6月前
|
Go 开发者
Golang深入浅出之-Go语言 defer、panic、recover:异常处理机制
Go语言中的`defer`、`panic`和`recover`提供了一套独特的异常处理方式。`defer`用于延迟函数调用,在返回前执行,常用于资源释放。它遵循后进先出原则。`panic`触发运行时错误,中断函数执行,直到遇到`recover`或程序结束。`recover`在`defer`中捕获`panic`,恢复程序执行。注意避免滥用`defer`影响性能,不应对可处理错误随意使用`panic`,且`recover`不能跨goroutine捕获panic。理解并恰当使用这些机制能提高代码健壮性和稳定性。
130 2
|
6月前
|
Java Go 区块链
【Go语言专栏】Go语言中的延迟执行与defer语句
【4月更文挑战第30天】Go语言的延迟执行与defer语句用于资源释放和错误处理。defer通过关键字定义,函数返回时执行,顺序与定义相反。参数在定义时求值。应用包括资源释放、错误处理、成对操作和函数包装,是Go编程的关键特性。
54 0
|
6月前
|
网络协议 BI Go
Go-异常处理(defer recover panic)
Go-异常处理(defer recover panic)
74 0
|
编译器 Go
Go学习笔记-defer、panic、recover分析
Go学习笔记-defer、panic、recover分析
84 1
Go学习笔记-defer、panic、recover分析
|
11月前
|
Go
go defer用法_类似与python_java_finially
go defer用法_类似与python_java_finially
65 0