代码异常处理是学习任何编程语言都需要考虑的一个重要话题。比如C++,python都引入exception的概念和try_catch try_except的引入。golang自然也有自己独特的异常处理方式。漂亮的异常处理方式也是golang语言最大的亮点之一,下面重点解析一下golang错误处理方式。
Go语言引入了一个关于错误处理的标准模式,即 error 接口,该接口的定义如下:
- type error interface {
- Error() string
- }
在golang代码中,对于大多数函数,如果要返回错误,大致上都可以定义为如下模式
- func myFunc(param string)(str string, err error) {
- // ...
- }
将 error 作为多种返回值中的最后一个,但这并非是强制要求
调用时的代码建议按如下方式处理错误情况
- _, err := myTest("test")
- if err != nil {
- // 错误处理
- } else {
- // ......
- }
同时,在代码中,我们可以自定义error类型,举例如下
- type DefineError struct {
- Define string
- Err error
- }
-
- // 定义Error函数
- func (d *DefineError) Error() string {
- return d.Define + d.Err.Error()
- }
-
这样,当函数调用失败返回 err 时,将该 err 包装到一个 DefineError 对象中返回
- func Stat() (err error) {
- err = myFunc()
- if err != nil {
- return nil, &DefineError{"define", err}
- }
- // ......
- }
在函数编写过程中,有时引入异常会导致代码异常退出,但是,之前打开的诸如文件句柄这些操作如果不关闭,会导致程序在运行过程中出现问题。而在golang语言中,通过defer关键字轻轻松松的解决了这个问题。
代码示例:
- package main
-
- import "fmt"
-
- func main() {
- defer fmt.Println("main defer:1")
- defer fmt.Println("main defer:2")
- fmt.Println("main --:1")
- panic("--- error ---")
- fmt.Println("main --:2")
- defer fmt.Println("main defer:5")
- defer fmt.Println("main defer:6")
- }
-
-
- /*
- main --:1
- main defer:2
- main defer:1
- panic: --- error ---
- goroutine 1 [running]:
- main.main()
- */
通过代码测试可以看出,当程序出现异常时,程序异常部分下面的代码将不再执行,而异常上面部分的defer代码,将在异常抛出后逆序执行。因此,当我们把要执行的句柄操作通过defer放在函数起始位置,无论程序执行是否异常,句柄关闭操作都能在程序里安全执行。
panic:在函数中如果书写并触发了panic语句,会终止其后要执行的代码。在panic所在函数内如果存在要执行的defer函数列表,则按照defer书写顺序的逆序执行,同时,如果该函数被其他函数调用,则调用函数在调用代码后面的代码都不会执行,如果存在defer语句,一样逆序执行。在代码最后,则抛出panic异常。代码示例:
- package main
-
- import "fmt"
-
- func main() {
- defer fmt.Println("main defer:1")
- defer fmt.Println("main defer:2")
- fmt.Println("main --:1")
- myTest()
- fmt.Println("main --:2")
- defer fmt.Println("main defer:5")
- defer fmt.Println("main defer:6")
- }
-
- func myTest() {
- defer fmt.Println("myTest defer:1")
- defer fmt.Println("myTest defer:2")
- fmt.Println("myTest --:1")
- panic("manaual error")
- defer fmt.Println("myTest defer:4")
- defer fmt.Println("myTest defer:5")
- }
-
- /*
- main --:1
- myTest --:1
- myTest defer:2
- myTest defer:1
- main defer:2
- main defer:1
- panic: manaual error
- goroutine 1 [running]:
- main.myTest()
- D:/code/go/go/01-错误演示.go:19 +0x165
- main.main()
- D:/code/go/go/01-错误演示.go:9 +0x173
- Process finished with exit code 2
- */
recover:
代码示例:
- package main
-
- import "fmt"
-
- func main() {
- defer fmt.Println("main defer:1")
- defer fmt.Println("main defer:2")
- fmt.Println("main --:3")
- myTest()
- fmt.Println("main --:4")
- defer fmt.Println("main defer:5")
- defer fmt.Println("main defer:6")
- }
-
- func myTest() {
- defer fmt.Println("---------------")
- defer func() {
- if msg := recover(); msg != nil {
- fmt.Println("panic信息:", msg, "---recover恢复---")
- }
- }()
- defer fmt.Println("myTest defer:1")
- defer fmt.Println("myTest defer:2")
- fmt.Println("myTest --:1")
- panic("manaual error")
- defer fmt.Println("myTest defer:4")
- defer fmt.Println("myTest defer:5")
- }
-
- /*
- Process finished with exit code 0
- */