12 Golang defer panic recover

learninginto · 2021-03-25 04:32:36 · 298 次点击 · 预计阅读时间 2 分钟 · 大约8小时之前 开始浏览    
这是一个创建于 2021-03-25 04:32:36 的文章,其中的信息可能已经有所发展或是发生改变。

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("继续执行...")
}
//给管理员发送邮件
//继续执行...

有疑问加站长微信联系(非本文作者)

本文来自:简书

感谢作者:learninginto

查看原文:12 Golang defer panic recover

入群交流(和以上内容无关):加入Go大咖交流群,或添加微信:liuxiaoyan-s 备注:入群;或加QQ群:692541889

298 次点击  
加入收藏 微博
暂无回复
添加一条新回复 (您需要 登录 后才能回复 没有账号 ?)
  • 请尽量让自己的回复能够对别人有帮助
  • 支持 Markdown 格式, **粗体**、~~删除线~~、`单行代码`
  • 支持 @ 本站用户;支持表情(输入 : 提示),见 Emoji cheat sheet
  • 图片支持拖拽、截图粘贴等方式上传