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 +0x27