专栏首页流浪猫的golanggo panic与recover分析及错误处理

go panic与recover分析及错误处理

先介绍一下什么叫error 类型

error 是一种类型,表示错误状态的类型,如果没有错误则是nil。直白点将:error 类型就是描述错误的一种类型。

panic 在golang goroutine 的作用 panic 官方文档介绍:

panic 是用来停止当前程序的执行。当一个方法调用panic。 当函数F调用panic时,F的正常执行立即停止。 但是任何有F推迟的函数都会运行,意思是F定义有defer关键字声明的函数会执行,然后F返回给它的调用者。 对于调用者G来说,F的调用就像调用panic 一样,终止G的执行并运行任何延迟(带有defer 关键字)的函数。 这种情况会持续下去,直到正在执行的goroutine中的所有功能都以相反的顺序停止。 此时,程序终止并报告错误情况,包括panic的参数值。最后这种情况可以通过调用recover 来恢复函数的运行。 函数 recover 介绍

recover内置函数允许一段程序管理一个正在paincing goroutine的行为。

在defer 定义的函数(不是由它调用的任何函数)内部执行一段recover 函数,通过recover函数执行来停止panic 函数的执行,并且可以找出给panic所传递的错误值。 如果在defer 函数之外调用恢复,它不会停止panic的执行。 在这种情况下,或者当goroutine没有panicing时,或者提供给panicing的参数为零时,恢复返回nil。 因此,recover函数的返回值报告协程是否正在遭遇panicing 。

panic函数就是往外扔错误,一层接一层往上扔直到当前程序不能运行为止,不想让panic 函数扔的错误导致程序挂掉,就得使用recover 函数来接收panic 错误或者说是阻挡panicing ,并且recover 函数可以将错误转化为error 类型。因为panic 错误不会让defer 关键字定义的函数也停止运行,就是说defer 关键字声明的函数或者代码即使遇到错误也会执行。 一个函数里面有defer 关键字声明一个函数(假设叫catch 函数)和要运行出错的代码,在catch 函数里面调用recover 函数。recover 会拦截错误,不会让错误往上扔,返回给调用者error(里面有错误的信息)类型 ,从而使goroutine 不挂掉。 上代码:

package main


import (
    "fmt"
    "errors"
)

func main() {
    testError()
    afterErrorfunc()
}

func testError() {
    //defer catch()
    panic(" \"panic 错误\"")
    fmt.Println("抛出一个错误后继续执行代码")
}
func  catch()  {
    if r := recover(); r != nil {
        fmt.Println("testError() 遇到错误:", r)
        var err error
        switch x := r.(type) {
        case string:
            err = errors.New(x)
        case error:
            err = x
        default:
            err = errors.New("")
        }
        if err != nil {
            fmt.Println("recover后的错误:",err)
        }
    }
}

func afterErrorfunc(){
    fmt.Println("遇到错误之后 func ")
}

运行结果:

panic:  "panic 错误"

goroutine 1 [running]:
main.testError()
    E:/goCode/src/MyTestGo/src/com.dylan.main/panic/testpanic.go:16 +0x40
main.main()
    E:/goCode/src/MyTestGo/src/com.dylan.main/panic/testpanic.go:10 +0x27

Process finished with exit code 2

当panic 函数执行的时候导致后面函数 afterErrorfunc() 不能执行,main函数也抛出一个错误,整个程序异常退出。 通过defer 关键字调用 catch函数。

func testError() {
    defer catch()
    panic(" \"panic 错误\"")
    fmt.Println("抛出一个错误后继续执行代码")
}

程序运行结果:

testError() 遇到错误:  "panic 错误"
recover后的错误:  "panic 错误"
遇到错误之后 func 
Process finished with exit code 0

分析:程序正常结束,没有因为panic(错误)而到导致程序终止挂掉。错误被recover 函数接收,转化为error类型的错误,最后输出“ recover后的错误: “panic 错误” ” 而且后面 afterErrorfunc()执行。

一般在写的时候这么写 不用定义catch 函数:

func main() {
    testError()
    afterErrorfunc()
}

func testError() {
    defer func() {
        if r := recover(); r != nil {
            fmt.Println("testError() 遇到错误:", r)
        }
    }()

    panic(" \"panic 错误\"")
    fmt.Println("抛出一个错误后继续执行代码")
}
func catch(err error) {
    if r := recover(); r != nil {
        fmt.Println("testError() 遇到错误:", r)

        switch x := r.(type) {
        case string:
            err = errors.New(x)
        case error:
            err = x
        default:
            err = errors.New("")
        }
    }
}

func afterErrorfunc() {
    fmt.Println("遇到错误之后 func ")
}

在发生panic 函数里面加入下述代码就可以拦截panicing, 并且不让程序挂掉和显示错误信息。

defer func() {
        if r := recover(); r != nil {
            fmt.Println("testError() 遇到错误:", r)
        }
    }()

最后如果想将错误信息返回给调用者可以这么做:

func main() {
    err := testError()
    if err != nil {
        fmt.Println("main 函数得到错误类型:", err)
    }
    afterErrorfunc()
}

func testError() (err error) {
    defer func() {
        if r := recover(); r != nil {
            fmt.Println("testError() 遇到错误:", r)
            switch x := r.(type) {
            case string:
                err = errors.New(x)
            case error:
                err = x
            default:
                err = errors.New("")
            }
        }
    }()
    panic(" \"panic 错误\"")
    fmt.Println("抛出一个错误后继续执行代码")
    return nil
}

func catch(err error) {
    if r := recover(); r != nil {
        fmt.Println("testError() 遇到错误:", r)
        switch x := r.(type) {
        case string:
            err = errors.New(x)
        case error:
            err = x
        default:
            err = errors.New("")
        }
    }
}

func afterErrorfunc() {
    fmt.Println("遇到错误之后 func ")
}

提前声明一个error 类型的变量。把错误信息传递给error变量,再把error变量返回给调用者。

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

我来说两句

0 条评论
登录 后参与评论

相关文章

  • golang 的container/list (一)

    问题1:有了slice,还要list做什么? 问题2:list的底层实现是什么? 带着这两个问题来什么有浅入深的学习golang 语言 。 首先来看...

    地球流浪猫
  • go 的入门之路 Socket 编程

    服务端监听本地IP(127.0.0.1)7777端口。当有客户端连接时,获得一个conn 对象,coon 对象是 interface Conn的实现者,

    地球流浪猫
  • golang mongoDB GridFS查询 存储 删除文件

    GridFS 用于存储和恢复那些超过16M(BSON文件限制)的文件(如:图片、音频、视频等),如果没有超过16m大小可以将数据保存在BSON数据中。 Gr...

    地球流浪猫
  • 在fedora下使用搜狗拼音输入法

    Linux下的拼音输入法实在是不敢恭维,还好有人把搜狗拼音输入法制作成了RPM包.安装此rpm包就可以在Linux下面使用搜狗拼音输入法及其字库了. 第一步,下...

    用户1214695
  • Qt官方示例-广播发送器

    Qt君
  • 再谈谈列表元素的删除

    之前(以及更早之前)都提到了列表元素的删除,也提到过几种方法,有兴趣的朋友可以去看看,其中一种个人比较倾向的写法大概是这个样子(C++):

    用户2615200
  • 一个高性能、轻量级的分布式内存队列系统--beanstalk

    静儿
  • 一个高性能、轻量级的分布式内存队列系统--beanstalk

    Beanstalk是一个高性能、轻量级的、分布式的、内存型的消息队列系统。最初设计的目的是想通过后台异步执行耗时的任务来降低高容量Web应用系统的页面访问延迟。...

    Java高级架构
  • 自动驾驶公司Momenta完成B2轮融资,凯辉领投GGV跟投

    千平 发自 凹非寺 量子位 出品 | 公众号 QbitAI ? 自动驾驶公司Momenta完成B2轮融资,凯辉中法创新基金领投,GGV跟投。据介绍,本轮融资将用...

    量子位
  • python史上最全列表知识

    python连载第十五篇~list列表 该篇整体结构如下: 列表定义 列表元素访问 修改,添加 各种删除方法 列表切片读取内容 列表排序 列表插入,复制 列表加...

    企鹅号小编

扫码关注云+社区

领取腾讯云代金券