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函数

总结:简而言之就是下面两句话

关于异常抛出与处理的更详细内容参考:
https://www.jianshu.com/p/18dfd4772cdb

上一篇 下一篇

猜你喜欢

热点阅读