1500字范文,内容丰富有趣,写作好帮手!
1500字范文 > recover 没有捕获异常_Golang学习笔记之错误处理error panic (抛出错误) recover(捕获错误...

recover 没有捕获异常_Golang学习笔记之错误处理error panic (抛出错误) recover(捕获错误...

时间:2023-08-21 13:41:33

相关推荐

recover 没有捕获异常_Golang学习笔记之错误处理error panic (抛出错误) recover(捕获错误...

一、error

错误表示程序中出现了异常情况。Go 语言通过内置的错误接口提供了非常简单的错误处理机制。• error类型是go语言的一种内置类型,使用的时候不用特定去import因为它本质上是一个接口

error类型是一个接口类型,这是它的定义:typeerrorinterface{

Error()string

}

(1)一个例子理解errorpackagemainimport("fmt"

"os")funcmain(){//试图打开一个并不存在的文件,这将会返回一个error

f,err:=os.Open("/test.txt")iferr!=nil{

fmt.Println(err)//nosuchfileordirectory

return

}

fmt.Println(f.Name(),"openedsuccessfully")

}

在go中处理错误的惯用方式是将返回的错误与nil进行比较。零值表示没有发生错误,而非零值表示存在错误。

(2)错误定制

上面也看到了error 有了一个签名为 Error() string 的方法。所有实现该接口的类型都可以当作一个错误类型。

第一、通过errors包去订制error

函数原型:func New(text string) error

使用字符串创建一个错误可以认为是New(fmt.Sprintf(...))。import"errors"//使用errors必须import"errors"包error:=errors.New("Myerror")iferror!=nil{

fmt.Print(err)//Myerror}

demopackagemainimport("errors"

"fmt"

"math")funccircleArea(radiusfloat64)(float64,error){ifradius

return0,errors.New("Areacalculationfailed,radiusislessthanzero")

}returnmath.Pi*radius*radius,nil

}funcmain(){

radius:=-20.0

area,err:=circleArea(radius)iferr!=nil{

fmt.Println(err)return

}

fmt.Printf("Areaofcircle%0.2f",area)

}

第二种、通过fmt.Errorf()去订制

函数原型:func Errorf(format string, a ...interface{}) error

Errorf根据format参数生成格式化字符串并返回一个包含该字符串的错误。err:=fmt.Errorf("error")iferr!=nil{

fmt.Print(err)

}

就不贴demo了

只需要把circleArea里if语句的返回值改为return0,fmt.Errorf("Areacalculationfailed,radius%.2fislessthanzero",radius)

第三种、使用结构体和字段来定制typeMyErrorstruct{errerror

}//订制Error()func(eMyError)Error()string{returne.err.Error()

}

funcmain(){

err:=MyError{

errors.New("error"),

}

fmt.Println(err.Error())

}

demopackagemainimport("fmt"

"math")typeareaErrorstruct{

errstring

radiusfloat64

}

func(e*areaError)Error()string{returnfmt.Sprintf("radius%0.2f:%s",e.radius,e.err)

}

func(e*areaError)IsRadiusNagative()bool{returne.radius

funccircleArea(radiusfloat64)(float64,error){ifradius

}returnmath.Pi*radius*radius,nil

}

funcmain(){

s,err:=circleArea(-20)iferr!=nil{//将错误转换为具体的类型

iferr,ok:=err.(*areaError);ok{

fmt.Printf("Radius%.2fislessthanzero",err.radius)return

}

fmt.Println(err)return

}

fmt.Println(s)

}

二、panic (抛出错误)和recover(捕获错误)

golang中没有try ... catch...这类异常捕获语句,但是提供了panic和recover内建函数,用于抛出异常以及异常的捕获。• panic、 recover 参数类型为 interface{},因此可抛出任何类型对象。

• 如果程序出现了致命的错误,导致整个程序无法进行下去,golang提供了panic函数,用来实现程序的退出。

• 当程序发生 panic 时,使用 recover 可以重新获得对该程序的控

制。

• 不是所有的panic异常都来自运行时,直接调用内置的panic函数也会引发panic异常

• panic函数接受任何值作为参数。

(1)panic的使用①延迟调⽤中引发的错误,可被后续延迟调⽤捕获,但仅最后⼀个错误可被捕获。functest(){deferfunc(){

fmt.Println(recover())

}()deferfunc(){

panic("deferpanic")

}()

panic("testpanic")

}funcmain(){

test()//deferpanic}②当函数发生 panic 时,它会终止运行,在执行完所有的延迟函数后,程序控制返回到该函数的调用方。这样的过程会一直持续下去,直到当前协程的所有函数都返回退出,然后程序会打印出 panic 信息,接着打印出堆栈跟踪,最后程序终止。

如果函数没有 panic,调用 recover 函数不会获取到任何信息,也不会影响当前进程。

demopackagemainimport("fmt")funcfullName(firstName*string,lastName*string){iffirstName==nil{

panic("FirsrNamecan'tbenull")

}iflastName==nil{

panic("LastNamecan'tbenull")

}

fmt.Printf("%s%s\n",*firstName,*lastName)

fmt.Println("returnednormallyfromfullName")

}functest(){

deferfmt.Println("deferredcallintest")

firName:="paul"

fullName(&firName,nil)

}funcmain(){

deferfmt.Println("deferredcallinmain")

test()

fmt.Println("returnednormallyfrommain")

}

输出

(2)recover的使用如果 goroutine 没有 panic,那调用 recover 函数会返回 nil。

捕获函数 recover 只有在延迟调⽤内直接调⽤才会终⽌错误,否则总是返回 nil。任何未捕获的错误都会沿调⽤堆栈向外传递。

修改一下上面的例子使用recover来捕获异常packagemainimport("fmt")funcrecoverName(){ifr:=recover();r!=nil{

fmt.Println("recoveredfrom",r)

}

}funcfullName(firstName*string,lastName*string){deferrecoverName()

iffirstName==nil{

panic("FirsrNamecan'tbenull")

}iflastName==nil{

panic("LastNamecan'tbenull")

}

fmt.Printf("%s%s\n",*firstName,*lastName)

fmt.Println("returnednormallyfromfullName")

}functest(){

deferfmt.Println("deferredcallintest")

firName:="paul"

fullName(&firName,nil)

}funcmain(){

deferfmt.Println("deferredcallinmain")

test()

fmt.Println("returnednormallyfrommain")

}

输出为:

当发生panic之后,当前函数使用了recover,则捕获了这个错误,交给上一层调用者,正常执行剩下的代码;如果当前函数没有使用recover,调用者使用了recover,则属于调用者捕获了错误,将权限交给调用者的调用者,之后正常执行recover函数捕捉了错误,但是这时我们并不容易发现错误的位置,那么可以在实现了recover函数的函数中使用debug.PrintStack(),这样就可以输出错误出现的函数,使用这个最先显示的行数是系统的,也就是stack.go包下的具体位置,这个会有两行,然后是调用debug.PrintStack()的地方,这个是自己写的函数,再然后就是系统的panic.go包,因为出错的时候的会调用这个包里面的函数,然后就是具体的错误位置了

函数原型:

func Stack() []byte

Stack 返回格式化的go程的调用栈踪迹。 对于每一个调用栈,它包括原文件的行信息和PC值;对go函数还会尝试获取调用该函数的函数或方法,及调用所在行的文本。

func PrintStack()

PrintStack将Stack返回信息打印到标准错误输出。

demoimport("fmt""runtime/debug")funcr(){ifr:=recover();r!=nil{

fmt.Println("Recovered",r)

debug.PrintStack()

}

}

作者:学生黄哲

链接:/p/18dfd4772cdb

本内容不代表本网观点和政治立场,如有侵犯你的权益请联系我们处理。
网友评论
网友评论仅供其表达个人看法,并不表明网站立场。