12 Golang defer panic recover

defer

Golang中的defer会将其后面跟随的语句进行延迟处理。在defer归属的函数即将返回时,将延迟处理的语句按defer定义的逆序执行。也就是说,最先被defer的语句最后被执行。

fmt.Println("开始")
defer fmt.Println(1)
defer fmt.Println(2)
defer fmt.Println(3)
fmt.Println("结束")
//开始
//结束
//3
//2
//1

defer在函数中必须是匿名自执行函数

func f1(){
    fmt.Println("开始")
    
    defer func(){
        fmt.Println("aaa") 
        fmt.Println("bbb") 
    }()
    
    fmt.Println("结束")
}
//开始
//结束
//aaa
//bbb
  • 对比f1和f2的返回值

匿名返回值

func f1(){
    var a int
    defer func(){
        a++
    }()
    return a
}

func main(){
    fmt.Println(f1())//0
}

命名返回值

func f2()(a int){
    defer func(){
        a++
    }
    return a
}

func main(){
    fmt.Println(f2())//1
}
  1. 返回值赋值
  2. 运行defer
  3. 执行return指令
  • demo
func f3()(x int){
    defer func(x int) {
        x++
    }(x)
    return 5
}

func main(){
    fmt.Println(f3())//5
}

defer注册要延迟执行的函数时,该函数所有的参数都需要确定其值

func calc (index string, a, b int) int {
    ret := a + b
    fmt.Println(index, a, b, ret)
    return ret
}
func main() {
    x := 1
    y := 2
    defer calc("AA", x, calc("A", x, y))
    x = 10
    defer calc("BB", x, calc("B", x, y))
    y = 20
}

注册顺序

    defer calc("AA", x, calc("A", x, y))//A 1 2 3
    defer calc("BB", x, calc("B", x, y))//B 10 2 12

执行顺序

    defer calc("BB", x, calc("B", x, y))//BB 10 12 22
    defer calc("AA", x, calc("A", x, y))//AA 1 3 4
panic/recover

Golang中目前没有异常机制,可以使用panic/recover模式来处理错误。

panic可以在任何地方引发,但recover只有在defer调用的函数中有效。

 func fn1(){
    fmt.Println("fn1")
 }
 func fn2(){
    panic("抛出一个异常")
 }
 func main(){
     fn1()
     fn2()
     fmt.Println("结束")
 }
 //fn1
 //抛出一个异常

可以看到,panic后面的程序终止执行了

  • recover和defer
 func fn1(){
    fmt.Println("fn1")
 }
 func fn2(){
   defer func(){
      err := recover() //如果没有异常,err默认为nil
      if err != nil {
          fmt.Println("err:",err)
      }
   }()
   panic("抛出一个异常")
 }
 func main(){
     fn1()
     fn2()
     fmt.Println("结束")
 }
// fn1
// err: 抛出一个异常
// 结束
  • demo1
func fn1(a int, b int) {
    defer func(){
        err := recover()
        if err != nil {
            fmt.Println("error",err)
        }
    }() 
    fmt.Println( a / b )
}

func main(){
    fn1(10, 0)
    fmt.Println("结束")
}
//error runtime error: integer divide by zero
//结束
  • demo2
//模拟读取文件的方法
func readFile(fileName string) error {
    if fileName === "main.go" {
        return nil
    } else {
        return errors.New("读取文件失败")
    }
}

func myFn(){
    defer func(){
       err := recover()
       if err != nil {
           fmt.Println("给管理员发送邮件")
       }
    }()
    err := readFile("xxx.go")
    if err != nil {
        panic(err)
    }
}

func main() {
    myFn()
    fmt.Println("继续执行...")
}
//给管理员发送邮件
//继续执行...

你可能感兴趣的:(12 Golang defer panic recover)