• 从零开始学Go之函数(三):宕机与恢复


    延迟执行defer:

    当某些语句需要函数结束时才使用时,可以使用defer语句

    最常用的就是在打开os.Open后加入Close()时用defer避免程序结束未关闭文件

    defer 语句

    例子:
    func main() {
     fmt.Println("test")
     for i:=0;i<3 ;i++ {
      fmt.Println(i)
      defer fmt.Println(i)
     }
    }

    运行结果:

    test

    0

    1

    2

    2

    1

    0

    文件操作例子:
     file, err := os.Open(filename)
     if err != nil {
       return err
     }
     /*
     这里defer要写在err判断的后边而不是os.Open后边
     如果资源没有获取成功,就没有必要对资源执行释放操作
     如果err不为nil而执行资源执行释放操作,有可能导致panic
     */
     defer file.Close()

    defer 语句会将函数推迟到外层函数返回之后执行。

    推迟调用的函数其参数会立即求值,但直到外层函数返回前该函数都不会被调用。推迟的函数调用会被压入一个栈中(后进先出)。

    当外层函数返回时,被推迟的函数会按照后进先出的顺序调用,可能会修改返回值从而得出不正确的结果。

     

    宕机panic:

    当需要在程序中手动触发宕机时,可以用内置的panic语句

    func panic(v interface{})

    在panic后剩下的代码都会不会执行,同时会将堆栈和 goroutine 信息输出到控制台

    func main() {
     fmt.Println("位置1")
     defer fmt.Println("defer位置1")
     fmt.Println("位置2")
     panic("手动崩溃")
     defer fmt.Println("defer位置2")
     fmt.Println("位置3")
    }

    运行结果

    panic: 手动崩溃

    位置1

    位置2

    defer位置1

    goroutine 1 [running]:

    main.main()

    D:/SoloWork/Learn/main.go:13 +0x13a

     

    恢复recover:

    recover是用来panic时使程序继续运行的函数

    func recover() interface{}

    使用方法是在panic前先defer声明一个闭包函数,让里面的recover捕捉panic异常,这样当后面遇到不重要的panic时能抛出错误又能让程序继续运行来处理这个错误。

    recover之后,逻辑并不会恢复到panic那个点去,函数还是会在defer之后返回,也就是说当前函数会中止,但上层函数会继续运行。

    例子:
    func main() {
     fmt.Println("位置1")
     defer fmt.Println("defer位置1")
     fmt.Println("位置2")
     defer func() { // 必须要先声明defer,否则不能捕获到panic异常
      fmt.Println("defer进入函数")
      if err := recover(); err != nil {
        fmt.Println(err) // 这里的err其实就是panic传入的内容
      }
      fmt.Println("defer错误处理")
     }()
     panic("崩溃")
     //这里开始向下不会执行
     defer fmt.Println("defer位置2")
     fmt.Println("位置3")
    }

    运行结果:

    位置1

    位置2

    defer进入函数

    崩溃

    defer错误处理

    defer位置1

    func ContinueRun(){
     defer func() { // 必须要先声明defer,否则不能捕获到panic异常
      fmt.Println("defer进入函数")
      if err := recover(); err != nil {
       fmt.Println(err) // 这里的err其实就是panic传入的内容
      }
      fmt.Println("defer错误处理")
     }()
     panic("崩溃")
     fmt.Println("位置4")
    }
    ​
    ​
    func main() {
     fmt.Println("位置1")
     defer fmt.Println("defer位置1")
     fmt.Println("位置2")
     ContinueRun()
     defer fmt.Println("defer位置2")
     fmt.Println("位置3")
    }

    运行结果:

    位置1

    位置2

    defer进入函数

    崩溃

    defer错误处理

    位置3

    defer位置2

    defer位置1

  • 相关阅读:
    Java 对象容器
    Java 类与对象
    Java 数组 字符 函数
    C++ 趣图
    数据管理系统想要实现的功能?
    Incorrect integer value: '' for column 'mid' at row 11366Incorrect integer value: '' for column 'mid' at row 1,自增字段为空,添加记录时出错
    关于汉字参数在链接参数中,接收后显示为问号乱码的问题该如何解决?
    原生js实现文字无缝向上滚动效果
    在php中如何用 union all统计总条数?
    在php中修改cookie值遇到的奇怪问题
  • 原文地址:https://www.cnblogs.com/VingB2by/p/11117739.html
Copyright © 2020-2023  润新知