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 +
相关文章
|
6月前
|
前端开发 UED
【面试题】async/await 函数到底要不要加 try catch ?
【面试题】async/await 函数到底要不要加 try catch ?
|
2月前
|
JavaScript 前端开发 Go
async 和 defer的作用与区别
async 和 defer的作用与区别
|
6月前
|
前端开发 JavaScript 开发者
阿珊带你深入理解 async/await 函数
阿珊带你深入理解 async/await 函数
|
2月前
|
前端开发 JavaScript
async和await的错误处理
在TypeScript中,`async`和`await`是处理异步操作的语法糖,能够让异步代码看起来像同步代码。`async`函数返回的总是`Promise`对象。当`await`后跟的表达式为`reject`状态的`Promise`时,会抛出错误,需要通过`try/catch`、链式`.catch()`或外部`Promise`包装来处理错误,防止代码崩溃。
110 0
async和await的错误处理
|
3月前
|
前端开发 JavaScript 小程序
【JS】async、await异常捕获,这样做才完美
本文通过生动的例子说明了在JavaScript中使用async/await时,不捕获异常可能导致的问题,并介绍了三种处理异步调用异常的方法:try-catch、使用Promise的`.catch`以及`await-to-js`插件库。通过这些方法,可以有效避免异常导致的程序中断,提升代码的健壮性和可读性。
73 0
【JS】async、await异常捕获,这样做才完美
|
JavaScript 前端开发 Go
async vs defer 的区别
async vs defer 的区别
75 0
|
6月前
|
前端开发 UED
【面试题】 async/await 函数到底要不要加 try catch ?
【面试题】 async/await 函数到底要不要加 try catch ?
【面试题】 async/await 函数到底要不要加 try catch ?
如何给所有的 await async 函数添加try/catch?
如何给所有的 await async 函数添加try/catch?
|
前端开发 UED
async/await 函数到底要不要加 try catch ?
async/await 函数到底要不要加 try catch ?
117 0
|
前端开发
循环中使用async_await
循环中使用async_await,多种方法,按需取用
76 0