Skip to content

Commit 454f4a7

Browse files
committed
defer 语句及使用示例
1 parent 441c288 commit 454f4a7

File tree

1 file changed

+66
-0
lines changed
  • 错误和异常处理/defer 语句及使用示例

1 file changed

+66
-0
lines changed
Lines changed: 66 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,66 @@
1+
/*
2+
defer func (){
3+
// 执行复杂的清理工作 ...
4+
}
5+
6+
另外,一个函数/方法中可以存在多个 defer 语句,defer 语句的调用顺序遵循先进后出的原则,即最后一个 defer 语句将最先被执行,
7+
相当于「栈」结构,如果在循环语句中包含了 defer 语句,则对应的 defer 语句执行顺序依然符合先进后出的规则。
8+
由于 defer 语句的执行时机和调用顺序,所以我们要尽量在函数/方法的前面定义它们,以免在后面执行时漏掉,尤其是运行时抛出错误会中断后面代码的执行,
9+
也就感知不到后面的 defer 语句。
10+
下面我们看一个简单的示例 defer.go:
11+
*/
12+
13+
package main
14+
15+
16+
import (
17+
"fmt"
18+
)
19+
20+
func printError(){
21+
fmt.Println("娄底执行")
22+
}
23+
24+
func main (){
25+
26+
// 栈结构,先进后出
27+
defer printError()
28+
defer func (){
29+
fmt.Println("除数不能为0!")
30+
}()
31+
32+
var i =1
33+
var j=0
34+
var k=i/j
35+
fmt.Printf("%d / %d = %d\n",i,j,k)
36+
}
37+
38+
/*
39+
这段代码中,我们定义了两个 defer 语句,并且是在函数最顶部,以确保异常情况下也能执行。
40+
41+
在函数正常执行的情况下,这两个 defer 语句会在最后一条打印语句执行完成后先执行第二条 defer 语句,再执行第一条 defer 语句
42+
43+
1 / 1 = 1
44+
除数不能为0!
45+
娄底执行
46+
47+
而如果我们把 j 的值设置为 0,则函数会抛出 panic:
48+
====================================================
49+
除数不能为0!
50+
娄底执行
51+
panic: runtime error: integer divide by zero
52+
53+
goroutine 1 [running]:
54+
main.main()
55+
D:/goLang/github/golang_project/错误和异常处理/defer 语句及使用示例/defer.go:34 +0x58
56+
exit status 2
57+
===================================================
58+
59+
表示除数不能为零,这个时候,也会执行 defer 语句,底层的逻辑是在执行 var k = i / j 这条语句时,遇到除数为0,
60+
则抛出异常 panic,然后立即中断当前函数 main 的执行(后续语句都不再执行),
61+
并按照先进后出顺序依次执行定义在当前函数中的 defer 语句,最后打印出 panic 日志及错误信息。
62+
关于 panic 及其内部执行逻辑,学院君将在下一篇教程给大家介绍。
63+
64+
总结一下,Go 语言的 defer 语句相当于 PHP 中析构函数和 finally 语句的功效,
65+
常用于定义兜底逻辑,在函数执行完毕后或者运行抛出 panic 时执行,如果一个函数定义了多个 defer 语句,则按照先进后出的顺序执行。
66+
*/

0 commit comments

Comments
 (0)