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 +