Go defer
最后修改于 2025 年 5 月 3 日
在本文中,我们将展示如何在 Golang 中使用 defer 语句延迟执行。
Go 中的 defer
语句允许将函数的执行推迟到其包含的函数完成为止。尽管被延迟,但函数调用的参数在 defer 语句出现的位置立即进行评估。
延迟的函数调用使用堆栈结构进行管理,这意味着它们遵循后进先出 (LIFO) 的执行顺序。因此,当包含的函数开始返回过程时,最近延迟的函数将是第一个执行的。这种行为对于确保正确的资源管理和清理特别有用。
defer
语句的一个常见应用是资源管理任务,例如关闭打开的文件、释放网络连接或释放数据库句柄。通过使用 defer
,开发人员可以确保清理操作始终如一地执行,即使函数由于错误或提前返回语句而过早返回。此外,延迟的调用可以与多个 defer
语句结合使用,从而允许按照声明的相反顺序执行多个清理操作。
除了资源清理之外,defer
还可以用于记录执行事件、测量执行时间或确保特定函数的最终化任务可靠运行。
Go defer 语句
以下是 Go defer
语句的一个简单演示。
package main import "fmt" func main() { defer fmt.Println("sky") fmt.Println("falcon") }
我们有两个 Println
函数调用。第一个是用 defer
关键字延迟的。
$ go run simple.go falcon sky
Go defer 参数评估
延迟函数的参数会立即进行评估。
package main import "fmt" func main() { fmt.Println("start") for i := 1; i <= 5; i++ { defer fmt.Println(i) } fmt.Println("end") }
defer
语句放在 for 循环内部。i
变量在循环执行期间进行评估。
$ go run arg_eval.go start end 5 4 3 2 1
Go defer 函数调用顺序
延迟的函数调用被放入一个堆栈中,并按照后进先出 (LIFO) 的顺序调用。
package main import "fmt" func main() { defer fmt.Println("one") defer fmt.Println("two") defer fmt.Println("three") defer fmt.Println("four") defer fmt.Println("4") defer fmt.Println("3") defer fmt.Println("2") defer fmt.Println("1") }
defer fmt.Println("one")
最先被延迟,最后执行。defer fmt.Println("1")
最后被延迟,最先执行。
$ go run defer_order.go 1 2 3 4 four three two one
Go defer 资源释放
defer
语句通常在释放必要资源(如打开的文件)时使用。
sky cloud cup wood rock sea tree oil book falcon
这是 words.txt
文件。
package main import ( "bufio" "fmt" "log" "os" ) func main() { f, err := os.Open("words.txt") if err != nil { log.Fatal(err) } defer f.Close() scanner := bufio.NewScanner(f) for scanner.Scan() { fmt.Println(scanner.Text()) } if err := scanner.Err(); err != nil { log.Fatal(err) } }
在代码示例中,我们逐行读取打开的文件。
f, err := os.Open("words.txt") if err != nil { log.Fatal(err) } defer f.Close()
打开 words.txt
文件并检查错误后,我们延迟调用 Close
方法。它在 main
函数结束时释放打开的文件。
Go defer 与 panic
即使函数发生 panic,延迟的函数调用也会被执行。
package main import "fmt" func main() { defer fmt.Println("sky") panic("terminating") fmt.Println("falcon") }
该示例在延迟 Println
函数后调用 panic
;它仍然会执行。
$ go run defpanic.go sky panic: terminating goroutine 1 [running]: main.main() /home/janbodnar/Documents/prog/golang/defer/defpanic/defpanic.go:7 +0xb9 exit status 2
来源
The Go Programming Language Specification
在本文中,我们介绍了 Golang 中的 defer 语句。