Go的Exception简介

Introduction

因为Go语言代码的简洁性,所以Go语言中不支持类似Java中的try…catch…finally这种异常处理,Go语言中的异常处理机制是使用:defer,panic和recover。

Defer

Defer可以理解为延迟函数,是用来添加函数结束时执行的语句。Defer使用不多的时候是不容易被理解的,遵循后进先出的原则,在这里暂时可以被理解为类似于栈的数据结构。实际上,在用go进行开发的过程中经常会用到defer方法,这个问题稍后研究之后再根据情况进行讨论和分析。

Panic

Panic是Go内置的一个函数,用来表示不可恢复的错误,Panic的参数可以是任意类型,传入的参数表示程序停止运行时需要输出的内容。当程序调用panic之后,就会直接停止运行,但是,当程序执行panic之后,不是立刻向上传递panic,而是先执行defer中的内容,然后再向上传递panic。

通过Panic的设计,我们很容易了解到应该尽量少的使用到panic,因为不管因为什么错误而导致整个程序崩溃这样都是不能被允许的,如果只是一个小小的工具中使用到了panic,导致主程序崩溃了,估计主程序开发会恨死你的插件。

Recover

根据上文我们可以知道,当函数执行过程中遇到panic后不会立刻返回,而是先defer再向上传递panic,所以如果在defer中,我们可以捕获到panic的话,阻止panic传递,异常处理机制就完善了。Go语言中提供了recover内置函数,一旦panic,我们会执行defer中的内容,因此我们可以在defer中调用recover函数捕获panic,如果可以捕获到panic就不会向上传递了。recover当且仅当在defer中才是有用的

以下,给出一个简单的代码作为示范:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
package main
import(
"fmt"
)
func main() {
defer func() { // 定义defer函数
if err := recover(); err != nil { // defer函数中执行recover捕获panic
fmt.Println("err message is ", err) // 捕获到之后输出错误信息
}
fmt.Println("defer func is built")
}()
for i := 0; i < 10; i++ {
fmt.Println(i)
if i == 3 {
fmt.Println("Panic")
panic(fmt.Sprintf("%v", i)) // 主动执行panic,且输出出问题的位置信息
}
}
}

执行结果如下:从结果中可以看出来,在执行for循环循环输出的过程中,当i=3的时候,执行了panic函数,参数是输出出错时候的位置信息,当遇到panic之后,程序就不再继续执行,而是跳转到defer函数中,进行错误信息的捕获。

WechatIMG1