defer延迟调用的详细用法
2018-12-10 本文已影响74人
Mr丶易客
***喜欢走一波***
defer是什么?
关键字 defer ⽤于注册延迟调⽤。这些调⽤直到 return前才被执⾏,通常⽤于释放资源或错误处理。
一、在没有错误的情况下,defer的执行顺序,与调用函数参数问题
先举个例子
package main
import (
"fmt"
)
//defer 压栈
func largest(num []int) {
defer fmt.Println("finished1")
defer fmt.Println("finished2")
item := num[0]
for _, v := range num {
if item < v {
item = v
}
}
println("最大值:", item)
}
func myInt(m int) {
fmt.Println(m)
}
func main() {
defer fmt.Println("main1")
m := 90
defer myInt(m) //defer 调用的函数参数值在压栈时已确定
m = 100
num := []int{1, 2, 3, 4, 5, 6}
largest(num) //多个defer的调用顺序
defer fmt.Println("main2")
}
执行结果
最大值: 6
finished2
finished1
main2
90 //这里输出是90
main1
根据上面的例子可以看出defer相当于一个栈,先进后出,并且defer调用的函数参数值在压栈时便已确定
二、关于defer与错误处理共同存在问题(简单一说)
panic 抛出错误, recover 捕获错误。
package main
import (
"fmt"
)
func myRecover() {
if r := recover(); r != nil { //捕获错误recover() 为捕获到为 nil
fmt.Println("MyRecovered", r)
// debug.PrintStack() //打印错误
}
fmt.Println("myRecover执行")
}
func a() {
defer myRecover()
arr := []int{1, 2, 3}
fmt.Println(arr[3]) //这是个错误 不存在arr[3],然后去执行defer
fmt.Println("Mya") //不执行
}
func main() {
defer myRecover() //此处defer 因为错误已经处理 所以捕获不到
a()
fmt.Println("MyMain")
}
执行结果
MyRecovered runtime error: index out of range
myRecover执行
MyMain
myRecover执行
对于panic的作用 和上面的arr[3]一样 都是用来抛出异常
package main
import (
"fmt"
)
//
//错误panic 的使用
func recoverName() { //recover
if r := recover(); r != nil {
fmt.Println("recovered from", r)
}
}
func fullName(firstName *string, lastName *string) {
// defer fmt.Println("defer fullName函数") //限制性defer在执行panic
defer recoverName() //捕获解决问题
if firstName == nil {
panic("First Name can't be null")
}
if lastName == nil {
panic("Last Name can't be null")
}
fmt.Printf("%s,%s\n", *firstName, *lastName)
fmt.Println("returned normallu from fullName")
}
func test() {
// defer recoverName()
// defer fmt.Println("defer test函数")
first := "Hello"
fullName(&first, nil)
}
func main() {
defer fmt.Println("defer main函数")
test()
fmt.Println("main overed")
}
输出结果
recovered from Last Name can't be null
main overed
defer main函数
总结:简而言之就是下面两句话
- 当发生panic之后,如果当前函数使用了recover,则捕获了这个 错误,权限交给上一层调用者,正常执行剩下的代码。
- 如果当前函数没有使用recover,上一层调用者函数使用了recover,则属于调用者捕获了错误,将权限交给上一层调用者的调用者 然后正常执行剩下代码
关于异常抛出与处理的更详细内容参考:
https://www.jianshu.com/p/18dfd4772cdb