博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
go语言之抛出异常
阅读量:5940 次
发布时间:2019-06-19

本文共 4898 字,大约阅读时间需要 16 分钟。

一: panic和recover 

作用:panic 用来主动抛出错误; recover 用来捕获 panic 抛出的错误。

概述: 1,引发panic有两种情况 1)程序主动调用panic函数 2)程序产生运行时错误,由运行时检测并抛出 过程: ! 发生 panic 后,程序会从调用 panic的函数位置或发生panic 的地方立即返回,逐层向上执行函数的defer语句, 然后逐层打印函数调用堆栈,直到被 recover 捕获或运行到最外层函数而退出。 ! panic的参数是一个空接口类型 interface{},所以任意类型的变量都可以传递给 panic(xxx) ! panic 不但可以在函数正常流程中抛出,在 defer 逻辑里也可以再次调用 panic 或抛出 panic a defer 里面的 panic 能够被后续执行的 defer 捕获。 recover()用来捕获 panic,阻止panic继续向上传递recover()和defer一起使用 ,但是recover() 只  有在defer后面的函数体内被直接调用才能捕获panic终止异常否则返回 nil,异常继续向外传递

//这会获取失败defer recover()defer fmt.println(recover())//嵌套两层也会获取失败defer func() {	func(){		println("defer inner")		recover() //无效	}()}

  以下场景会获取成功

package mainfunc f(){    defer func() {        println("defer inner")        recover()    }()}func except()  {    recover()}func test(){    defer except()    panic("test panic")}func main()  {    f()    except()    test()}

  可以有多个panic被抛出,连续多个panic的场景只能出现在延迟调用里面,否则不会出现多个panic被抛出的场景。但只有最后一次panic能被捕获

package mainimport "fmt"func main(){    defer func() {        if err :=recover();err !=nil{            fmt.Println(err)        }    }()  //只有最后一次panic调用被捕获    defer func() {        panic("first defer panic")   //打印结构是这个    }()    defer func() {        panic("second defer panic")    }()    panic("main body panic")}

  包中 in it 函数引发的 panic 只能在 in it 函数中捕获,在 main 中无法被捕获,原因是 in it

数先于 main 执行,函数并不能捕获内部新启动的 goroutine 所抛出的 panic 。

package mainimport (    "fmt"    "time")func do()  {    //这里并不能获取da函数中的panic    defer func() {        if err := recover();err != nil{            fmt.Println(err)        }    }()    go da()    go db()    time.Sleep(3*time.Second)}func da(){    panic("panic da")    for i := 0; i<10; i++{        fmt.Println(i)    }}func db(){    for i := 0; i<10; i++{        fmt.Println(i)    }}func main()  {    fmt.Println(do)    fmt.Println(da)    fmt.Println(db)}

  示例

package mainimport "fmt"//系统抛异常func test01() {    a := [5]int{
0, 1, 2, 3, 4} //a[10] = 123 index := 10 a[index] = 123}func main() { //panic: runtime error: index out of range //test01() //test02() //test03() test04()}//自己抛异常func test02() { getCircleArea(-5)}func getCircleArea(radius float32) (area float32) { if radius < 0 { //抛异常 panic("半径不能为负数") } return 3.14 * radius * radius}func test03() { //延时执行匿名函数 //延时到什么时候?要么正常结束,要么出异常 //recover()是复活的意思 defer func() { if err := recover(); err != nil { fmt.Println(err) } }() //会报错 getCircleArea(-5) //下句话没有打印 fmt.Println("这里有没有执行?")}func test04() { test03() fmt.Println("GAME OVER")}

返回异常

package mainimport (   "errors"   "fmt")//算半径func getCircleArea(radius float32) (ret float32, err error) {   if radius < 0 {      //创建异常      err = errors.New("沙雕,半径不能为负数")      return   }   ret = 3.14 * radius * radius   return}func main() {   ret, err := getCircleArea(5)   if err != nil {      fmt.Println(err)   } else {      fmt.Println("ret=", ret)   }}

使用场景:

(1)程序遇到了无法正常执行下去的错误,主动调用 panic 函数结束程序运行(2)在调试程序时,通过主动调用 panic 实现快速退出, panic 打印出的堆枝能够更快地定位错误。

为了保证程序的健壮性,需要主动在程序的分支流程上使用 recover()拦截运行时错误。

Go 提供了两种处理错误 方式,一 种是借助 panic和 recover 的抛出捕获机制,另一种使用error 错误类型

error:

go 语言内置错误接口类型任何类型只要实现 error() string 方法,都可以传递 eηor接口类型变量。 Go 语言典型的错误处理方式是将error作为函数最后一个返回值 在调用函数通过检测其返回的error值是否为nil来进行错误处理。
type  error interface{        Error()  string}

  

• 在多个返回值的函数中,error 通常作为函数最后一个返回值• 如果一个函数返回error 类型变量 ,则先用if语句处理 error != nil 异常场景,正常逻辑放到 if 语句块的后面,保持代码平坦。• defer 吾句应该放到四判断的后面,不然有可能产生 panic• 在错误逐级向上传递的过程中,错误信息应该不断地丰富和完善,而不是简单地抛出下层调用的错误。这在错误日志分析 非常有用和友好。

错误和异常

广义上的错误: 发生非期望的行为。狭义的错误:发生非期望的己知行为,这里的己知是指错误的类型是预料并定义好的。异常: 发生非期待的未知行为。这里的未知是指错误的类型不在预先定义的范围内。异常又被称为未捕获的错误( untrapped error )。程序在执行时发生未预先定义的错误,程序编译器和运行时都没有及时将其捕获处理。而是由操作系统进行异常处理,比如 语言程序里面经常出现的 Segmentation Fault (段异常错误),这个就属于异常范畴。

Go 是一门类型安全的语言,其运行时不 出现这种编译器和运行时都无法捕获的错 ,也就是说,

不会出现 untrapped error ,所以从这个角度来说, Go 语言不存在所谓的异常,出现的“异常”全是错误

Go 程序需要处理的这些错误可 分为两类1   一类是运行时错误( runtime errors ),此类错误语言的运行时能够捕获,并采取措施一一隐式或显式地抛出 panic2  一类是程序逻辑错误:程序执行结果不符合预期,但不会引发运行时错误对于运行时错误程序员无法完全避免其发生,只能尽量减少其发生的概率,并在不影响程序主功能的分支流程上“ rcover ”这些 panic,避免其因为一个panic引发整个程序的崩溃。

Go 对于错误提供了两种处理机制:

(1) 通过函数返回错误类型的值来处理错误。(2) 通过 panic 打印程序调用枝,终止程序执行来处理错误。所以对错误的处理也有两种方法,    一种是通过返回 个错误类型值来处理错误,    另一种是直接调用 panic 抛出错误,退出程序。Go 是静态强类型语言,程序的大部分错误是可以在编译器检测到的,但是有些错误行为需要在运行期才能检测出来。此种错误行为将导致程序异常退出 。其表现出的行为就和直接调用panic 一样 打印出函数调用技信息,并且终止程序执行在实际的编程中,error和panic 的使用应该遵循如下三条原则:1)程序局部代码的执行结果不符合预期,但此种行为不是运行时错误范围内预定义的错误,此种非期望的行为不会导致程序无法提供服务,此类场景应该使用函数返回 rror 类型变量进行错误处理。2)程序执行过程中发生错误,且该种错误是运行时错误范围内预定义的错误,此时 Go语言默认的隐式处理动作就是调用 panic ,如果此种 panic 发生在程序的分支流程不影响主要更能,则可以在发生 panic 的程序分支上游处使用 recove 进行捕获,避免引发整个程序的崩溃。3)程序局部代码执行结果不符合预期,此种行为虽然不是运行时错误范围内预定义的错误,但此种非期望的行为会导致程序无法继续提供服务,此类场景在代码中应该主动调用 panic终止程序的执行。进一步浓缩为两条规则(1)程序发生的错误导致程序不能容错继续执行,此时程序应该主动调用 panic 或由运行时抛出 panic(2)程序虽然发生错误 但是程序能够容错继续执行,此时应该使用错误返回值的方式处理错误,或者在可能发生运行时错误的非关键分支上使用 recover 捕获 panic

 

转载于:https://www.cnblogs.com/liucsxiaoxiaobai/p/10805788.html

你可能感兴趣的文章
SpringMVC常用注解标签详解
查看>>
day18 Set集合
查看>>
Oracle event之db file read
查看>>
ORA 00600 [ktrexc_1]
查看>>
Docker 安装
查看>>
查询文件系统容量与每个目录的容量
查看>>
如何确定一个网站是用Wordpress开发的
查看>>
我的友情链接
查看>>
我的友情链接
查看>>
wdcp 安装
查看>>
C语言运算符优先级相关问题
查看>>
MP4视频播放器代码
查看>>
Nginx 匹配 iphone Android 微信
查看>>
ldap
查看>>
Yum软件仓库配置
查看>>
linux 压缩与解压总结
查看>>
mysql脚本1064 - You have an error in your SQL syntax; check the manual
查看>>
nessus 本地扫描(一)
查看>>
linux服务器磁盘陈列
查看>>
python----tcp/ip http
查看>>