-
博文分类专栏
- Jquery基础教程
-
- 文章:(15)篇
- 阅读:46566
- shell命令
-
- 文章:(42)篇
- 阅读:154239
- Git教程
-
- 文章:(36)篇
- 阅读:234850
- leetCode刷题
-
- 文章:(76)篇
- 阅读:131794
-
Go的异常处理defer, panic, recover以及错误处理2018-03-21 22:04 阅读(5889) 评论(1)
一、异常处理
在异常处理方面,Go语言不像其他语言,使用try..catch.. finall..., 而使用defer, panic, recover,将异常和控制流程区分开。即通过panic抛出异常,然后在defer中,通过recover捕获这个异常,最后处理。
先来看一个案例吧,如下:
func main() { //立即执行函数 defer func(){ // 声明defer, fmt.Println("----调用 defer1 start----") if err:=recover(); err!=nil{ fmt.Println(err) // 这里的err其实就是panic传入的内容 } fmt.Println("----调用 defer1 end----") }() defer func(){ // 声明defer, fmt.Println("----调用 defer2 start----") if err:=recover(); err!=nil{ fmt.Println(err) // 这里的err其实就是panic传入的内容 } fmt.Println("----调用 defe2r end----") }() panic("测试") }
执行结果:
defer的思想类似于C++中的析构函数,就是在程序结束前执行的语句,defer后面可以是一个立即执行函数,也可以是一条语句。
defer可以多次,这样形成一个defer栈,后添加的会先被调用。
panic 是用来表示非常严重的不可恢复的错误的。在Go语言中这是一个内置函数,接收一个interface{}类型的值(也就是任何值了)作为参数。
panic的作用就像我们平常接触的异常,所以,调用panic会让程序不会继续往下执行(除非recover)。
recover捕获异常后的异常,不能再次被recover捕获。
二、错误处理
Go标准包提供的错误处理功能,error是个interface,如下:
type error interface { Error() string }
且go提供了errorString结构体,其则实现了error接口,如下:
// errorString is a trivial implementation of error. type errorString struct { s string } func (e *errorString) Error() string { return e.s }
在errors包中,还提供了New函数,来实例化errorString,如下:
// New returns an error that formats as the given text. func New(text string) error { return &errorString{text} }
于是,在定义函数的时候,我们就可以如下:
func add(args ... int) (int, error){ var sum int if len(args) == 0 { return 0, errors.New("参数为空") } for _ ,arg := range args { sum += arg } return sum, nil }
调用:
//立即执行函数 sum , err := add() if err != nil { fmt.Println(err.Error()) } else { fmt.Println(sum) }
输出:
当然,我们也可以自己去实现error接口,如下:
type myError struct { curFile string code int description string } //实现Error方法,那么myError就实现了error接口 func (e *myError) Error() string { return e.description }
然后在函数中,使用我们自己定义的错误,如下:
func add(args ... int) (int, error) { var sum int if len(args) == 0 { return 0, &myError{curFile: "test.go", code: -1, description: "参数不能为空哦!"} } for _, arg := range args { sum += arg } return sum, nil }
三、案例
1、案例1
下面程序的输出:
package main import ( "fmt" ) func main() { doTest() } func doTest() { defer func() { panic("报错2") }() defer func() { panic("报错1") }() panic("报错3") }
解析:defer可以多次,这样形成一个defer栈,后添加的会先被调用,所以输出“报错1”应该在“报错2”之前,且defer有点类似析构函数,所以输出“报错3”在“报错1”之前。
上面程序输出如下:
2、案例2
下面程序的输出:
package main import ( "fmt" ) func main() { doTest() fmt.Println("main捕获到错误:", recover()) } func doTest() { defer func() { fmt.Println("1捕获到错误:", recover()) }() fmt.Println("2捕获到错误:", recover()) panic("报错3") }
分析: recover 只有在 defer 调用的函数中才有效,否则当panic时,recover无法捕获到panic,变回输出nil。
上面程序输出如下: