Go语言学习日记【三十二】golang代码错误处理【error,defer,recover】
原创
©著作权归作者所有:来自51CTO博客作者wx6347c4235109b的原创作品,请联系作者获取转载授权,否则将追究法律责任
前言:
代码异常处理是学习任何编程语言都需要考虑的一个重要话题。比如C++,python都引入exception的概念和try_catch try_except的引入。golang自然也有自己独特的异常处理方式。漂亮的异常处理方式也是golang语言最大的亮点之一,下面重点解析一下golang错误处理方式。
一、error接口
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}
}
// ......
}
二、defer
在函数编写过程中,有时引入异常会导致代码异常退出,但是,之前打开的诸如文件句柄这些操作如果不关闭,会导致程序在运行过程中出现问题。而在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与recover
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:
- recover的作用是捕获panic,从而恢复正常代码执行;
- recover必须配合defer使用;
- recover没有传入参数,但是有返回值,返回值就是panic传递的值
代码示例:
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
*/