参考文献 https://juejin.im/post/6844903865561645070
参考文献 https://www.cnblogs.com/tinywan/p/8570898.html](https://www.cnblogs.com/tinywan/p/8570898.html
1. 什么是defer
defer用来声明一个延迟函数,把这个函数放入到一个栈上, 当外部的包含方法return之前,返回参数到调用方法之前调用,也可以说是运行到最外层方法体的"}"时调用。我们经常用他来做一些资源的释放,比如关闭io操作
func doSomething(fileName string) {
file,err := os.Open(fileName)
if err != nil {
panic(err)
}
defer file.Close()
}
defer 可以保证方法可以在外围函数返回之前调用。有点像其他言的 try finally
try{
}finally{
}
2. defer 读写外部变量
defer声明的函数读写外部变量,和闭包差不多。比如下面的代码
func doSomething() {
v := 10
defer func() {
fmt.Println(v)
v++
fmt.Println(v)
}()
v += 5
}
输出为
15
16
就像闭包一样,如果不是defer函数方法内的变量会向上一层函数访问变量,重新做计算。
3. defer 读写命名的返回值
这个例子中,defer声明的方法,给命名的返回值自增1
1 func doSomething() (rev int) {
2 defer func() {
3 rev++
4 }()
5
6 return 5
7 }
第6行的return 相当于
return rev = 5
defer 声明的匿名函数会在return 之前执行,相当于
rev = 5
// 执行defer方法
rev++
//然后return
return
所以结果是6
我把代码做一点点修改
1 func doSomething() (rev int) {
2 v := 10
3 defer func() {
4 v++
5 }()
6
7 return v
8 }
第7行返回的是局部变量v.
return v 相当于 return rev = v
defer 函数里是对局部变量v的操作,所以与返回的rev没有关系。
所有执行的结果是:10
4. defer 执行顺序
当有多个defer时执行顺序逆向的,后进先出:
func doSomething() {
defer fmt.Println(1)
defer fmt.Println(2)
}
会先输出2,再输出1
5. defer 处理异常
panic抛出异常后,如果不处理应用程序会崩溃。为了防止程序崩溃,我们可以在defer的函数里使用recover来捕获中异常:
func doSomething() {
defer func() {
if err := recover(); err != nil {
fmt.Print(err)
}
}()
fmt.Println("Running...")
panic("run error")
}
输出:
Running...
run error
recover 会捕获panic的异常。我再把代码做一点点修改:
func doSomething() {
defer func() {
if err := recover(); err != nil {
fmt.Print(err)
}
}()
defer func() {
panic("defer error")
}()
fmt.Println("Running...")
panic("run error")
}
输出结果
Running...
defer error
因为 recover()只捕获最后一次panic
6. defer 调用的函数参数的值在 defer 定义时就确定了
func main() {
i := 1
defer fmt.Println("Deferred print:",i)
i++
fmt.Println("Normal print:", i)
}
输出:
Normal print: 2
Deferred print: 1
有疑问加站长微信联系(非本文作者)