Golang —— 错误处理方案

Golang漂亮的错误处理规范也是Go语言的最大亮点之一。

error接口

标准库把error定义为接口类型, 以便于自己定义错误类型

type error interface{
    Error() string
}

error的使用也比较简单

	// error对象的两种创建方式
	// 1.使用fmt.Errorf
	//var err1 error = fmt.Errorf("%s", "this is normal error")
	err1 := fmt.Errorf("%s", "this is normal error")
	fmt.Println("err1 = ", err1)
	// 2. 使用errors.New()创建
	err2 := errors.New("this is normal error2")
	fmt.Println("err2 = ", err2)

再看看error的基本使用。
对于大多数函数,如果要返回错误,大致都可以定义为如下模式,将error作为返回值的最后一个,但这并非是强制要求的:

func Foo (param int) (n int, err error) {
	//...
}

调用时的代码建议按照如下的方式进行处理错误

n, err := Foo(0)

if err != nil {
	// 错误处理
} else {
	// 使用返回值n进行逻辑处理
}

举个栗子说明一下:

func TestUseError() {
	result, err := MyDiv(10, 0)
	if err != nil {
		// err不为空,那就说明出错了,那就打印错误信息
		fmt.Println("err = ", err)
	} else {
		// err为空,那就说明没有错误,那就打印结果
		fmt.Println("result = ", result)
	}
}

func MyDiv(a, b int) (res int, err error) {
	if b == 0 {
		err = errors.New("分母不能为0")
	} else {
		res = a / b
	}
	return
}

自定义error类型

因为Go语言接口的灵活性,根本不需要从error接口继承或者像Java一样使用implement来声明继承自哪个接口,具体代码如下:

type pathError struct {
	Op string
	Path string
	Err error
}
func (e *Patherror) Error() string {
	return e.Op + " " + e.Path + ": " + e.Err.Error()
}

panic()和recover()

Go语言中有两个内置函数panic()和recover()用来报告和处理运行时错误和程序中的错误。

  • error用于返回错误信息
  • panic()函数用于处理运行时异常,例如下标越界,空指针等,当panic异常发生时,程序会中断运行
  • recover()函数用于终止错误处理流程,也就是可以用来捕获并返回panic提交的错误内容,并使程序不要中断运行,但是recover()函数必须在defer中设置(连续调用panic,仅仅最后一个会被recover捕获)

一般recover的代码模板为:

defer func() {
	if err:= recover(); err != nil {
		fmt.Println(err)
	}
}()
foo()
// 无论foo()中是否会触发错误处理流程,该匿名defer函数都会在函数退出时得到执行。
// 假如foo()触发了错误处理流程,recover()函数执行将会使得该错误流程终止。
// 如果错误处理流程被触发,程序传给panic函数的参数不为nil,那么err中存的错误信息将会被打印出来。

下面在实践中体会一下panic和recover的使用

func TestUsePanicAndRecover() {
	test1()
	test2(20)
	test3()
}
func test1() {
	fmt.Println("1111111111111111111")
}

func test2(x int) {
	//如果不想让程序崩溃,那就需要设置一个recover()函数
	defer func() {
		//recover() // 直接调用recover()函数,结果就是这段代码直接跳过
		// 选择打印recover(),这样就可以把panic中的错误信息打印出来
		if err := recover(); err != nil {
			// 这里加一个判断,如果这里出错了,那么err就不为空,那就打印recover中的内容,否则
			fmt.Println(err)
		}
	}() // () 在这里是调用匿名函数
	var a [10]int
	a[x] = 100000 //这里会报一个数组下标越界的异常,产生一个panic,导致程序崩溃
}

func test3() {
	fmt.Println("3333333333333333333333")
}

上一篇:Golang错误处理机制(error 与 panic)


下一篇:Rust Lang Book Ch.9 Error Handling