10个 defer 技巧

简介: 10个 defer 技巧

Go的defer关键字是一个强大的工具,它允许你指定一个函数调用在以后执行,通常是在周围的函数返回之后。虽然看起来是一个简单的概念,但defer关键字可以用几种高级的方式来提高Go代码的效率和可靠性。


defer关键字的作用是当外围函数返回之后才执行被推迟的函数。


首先记住一点重要的原则:defer函数在外围函数返回之后,以后进先出(LIFO)的原则执行。


在这篇文章中,我们将探讨在Go中使用defer的十个技巧。从取消事件和释放资源到打印函数使用的时间和从panic中恢复,这些技巧将帮助你把你的Go技能提高到一个新的水平。无论你是想了解更多关于defer的初学者,还是想拓展知识面的经验丰富的开发者,这篇文章都能满足你的需求。


1.推迟一个函数调用,在周围的函数返回后执行:


func main() {
 defer fmt.Println("This will be printed after main returns")
}


2.推迟一个函数调用,按照它们被推迟的相反顺序执行:


func main() {
  defer_call()
}
func defer_call() {
  defer func() { fmt.Println("打印前") }()
  defer func() { fmt.Println("打印中") }()
  defer func() { fmt.Println("打印后") }()
}


3.即使发生恐慌,也要推迟一个函数的调用执行:


func main() {
 defer func() {
  if r := recover(); r != nil {
   fmt.Println("从 panic 中恢复:", r)
  }
 }()
 // This will cause a panic
 a := []int{1, 2, 3}
 fmt.Println(a[3])
}


4.推迟函数调用以关闭一个文件:


func main() {
 file, err := os.Open("test.txt")
 if err != nil {
  fmt.Println(err)
  return
 }
 defer file.Close()
 // Do something with the file
}


5.推迟一个函数调用来解锁一个mutex


func main() {
 var mutex sync.Mutex
 mutex.Lock()
 defer mutex.Unlock()
 // Do something that requires the mutex to be locked
}


6.推迟一个函数调用来减少一个 waitgroup


func main() {
 var wg sync.WaitGroup
 wg.Add(1)
 defer wg.Done()
 // Do something that requires the wait group to be waited on
 wg.Wait()
}


7.推迟一个函数调用来回滚一个事务:


func main() {
 tx, err := db.Begin()
 if err != nil {
  fmt.Println(err)
  return
 }
 defer tx.Rollback()
 // Do something with the transaction
 err = tx.Commit()
 if err != nil {
  fmt.Println(err)
  return
 }
}


8.推迟函数调用以释放一个资源:


func main() {
 resource, err := AcquireResource()
 if err != nil {
  fmt.Println(err)
  return
 }
 defer ReleaseResource(resource)
 // Do something with the resource
}


9.推迟一个函数的调用,打印一个函数所花费的时间:


func main() {
 start := time.Now()
 defer fmt.Printf("Time taken: %v\n", time.Since(start))
 // Do something that takes time
}


10.执行多个 defer 方法


首先记住一点重要的原则:defer函数在外围函数返回之后,以后进先出(LIFO)的原则执行。


defer fmt.Println("A")
defer fmt.Println("B")
defer fmt.Println("C")


总之,Go中的defer关键字允许你将一个函数调用安排在一个较晚的时间点上执行,即在周围函数返回之后。这对于清理资源、释放锁、回滚事务以及执行其他类型的延迟执行等任务非常有用。


defer语句可以被多次使用,延迟的函数调用将按照后进先出的顺序执行。这对堆叠多个延迟任务很有用,如关闭多个文件或释放多个锁。

总的来说,defer关键字是一个强大而方便的工具,可以确保Go程序中的某些任务总是被执行,而不管程序的流程如何。


面试题


func main() {
  defer_call()
}
func defer_call() {
  defer func() { fmt.Println("打印前") }()
  defer func() { fmt.Println("打印中") }()
  defer func() { fmt.Println("打印后") }()
  panic("触发异常")
}


output:


// 打印后 
// 打印中 
// 打印前 
// panic: 触发异常 
// goroutine 1 [running]: 
// main.defer_call() 
// C:/Users/Administrator/go/src/github.com/timliudream/go-test/Interview/1/interview1.go:16 +0xe7 
// main.main() 
// C:/Users/Administrator/go/src/github.com/timliudream/go-test/Interview/1/interview1.go:8 +
相关文章
|
2月前
|
JavaScript 前端开发 Go
async 和 defer的作用与区别
async 和 defer的作用与区别
|
JavaScript 前端开发 Go
async vs defer 的区别
async vs defer 的区别
69 0
|
6月前
|
Java Go
浅谈defer、panic、recover 三者的用法
浅谈defer、panic、recover 三者的用法
40 0
|
6月前
|
网络协议 BI Go
Go-异常处理(defer recover panic)
Go-异常处理(defer recover panic)
70 0
如何给所有的 await async 函数添加try/catch?
如何给所有的 await async 函数添加try/catch?
|
存储 编译器 Go
Go的defer
在Go语言中,defer是一个关键字,用于延迟执行函数或方法的调用。当使用defer关键字时,被延迟执行的函数或方法会在包含它的函数返回之前被调用。
53 0
|
前端开发 UED
async/await 函数到底要不要加 try catch ?
async/await 函数到底要不要加 try catch ?
109 0
|
Go API
script标签中defer和async有什么不同?
script标签中defer和async有什么不同?
106 0
script标签中defer和async有什么不同?
defer延迟语句
快速学习defer延迟语句
defer延迟语句