GO 错误处理

概述

Go语言追求简洁优雅,所以,Go语言不支持传统的 try…catch…finally 这种异常,因为Go语言的设计者们认为,将异常与控制结构混在一起会很容易使得代码变得混乱。因为开发者很容易滥用异常,甚至一个小小的错误都抛出一个异常。在Go语言中,使用多值返回来返回错误。不要用异常代替错误,更不要用来控制流程。在极个别的情况下,也就是说,遇到真正的异常的情况下(比如除数为 0了)。才使用Go中引入的Exception处理:defer, panic, recover

这几个异常的使用场景可以这么简单描述:Go中可以抛出一个panic的异常,然后在defer中通过recover捕获这个异常,然后正常处理。

当然不可能说,只处理真正的异常,那正常的逻辑错误,用户输入不符合预期这种错误怎么办?所以go 中 还有一个error 接口,一般来说:

  • error:一般用于表达可以被处理的错误

  • panic:一般用于表达非常严重不可恢复的错误

error本质

error只是一个内置的接口

我们可以去看看类型定义,在你 安装路径\src\builtin\builtin.go,中可以找到

// The error built-in interface type is the conventional interface for
// representing an error condition, with the nil value representing no error.
type error interface {
	Error() string
}

image-20230202104033387

error 本质上是个接口,既然是个接口,那我们就可以自己实现,也就是说我们可以自定义 错误处理

自定义error 处理

​ 例:

package main // 声明 main 包,表明当前是一个可执行程序

type MyError struct{}

// 实现error接口
func (m *MyError) Error() string {
	return "这是自定义的错误"
}

func main() { // main函数,是程序执行的入口
	// 假设这是用户的输入
	input := 0
	if input == 0 {
		err := &MyError{}
		println(err.Error())
		return
	}
	println("这里是正常流程")
}

image-20230202105259602

errors包

go 内置了一个 errors,来帮我们快速处理错误相关的东西

  • New() 创建一个新的 error
  • Is() 判断是不是特定的某个error
  • As() 类型转换为特定的error
  • Unwrap() 解除包装,返回被包装的 error

例:

package main

import (
	"errors"
	"fmt"
)

type MyError struct {
}

func (m *MyError) Error() string {
	return "Hello, it's my error"
}

func ErrorsPkg() {
	// 创建一个error
	// er := errors.New("this is new error")

	err := &MyError{}
	// 使用 %w 占位符,返回的是一个新错误
	// wrappedErr 是一个新类型,fmt.wrapError
	wrappedErr := fmt.Errorf("this is an wrapped error %w", err)

	// 再解出来
	if err == errors.Unwrap(wrappedErr) {
		fmt.Println("unwrapped")
	}

	if errors.Is(wrappedErr, err) {
		// 虽然被包了一下,但是 Is 会逐层解除包装,判断是不是该错误
		fmt.Println("wrapped is err")
	}

	copyErr := &MyError{}
	// 这里尝试将 wrappedErr转换为 MyError
	// 注意我们使用了两次的取地址符号
	if errors.As(wrappedErr, &copyErr) {
		fmt.Println("convert error")
	}
}

func main() {
	var err error = &MyError{}
	println(err.Error())

	ErrorsPkg()
}

image-20230202111052619

error 和 panic 选用哪个?

  • 遇事不决选 error
  • 当你怀疑可以用 error 的时候,就说明你
  • 不需要 panic 一般情况下,只有快速失败的过程,才会考虑panic

从 panic 中恢复

某些时候,你可能需要从 panic 中恢复过来:

比如某个库,发生 panic 的场景是你不希 望发生的场景。 这时候,你需要我们的 recover

如果你自己panic了,然后又要恢复过来,那么应该考虑 不要用panic

例:

package main

import "fmt"

func main() {
	defer func() {
		if data := recover(); data != nil {
			fmt.Printf("hello, panic: %v\n", data)
		}
		fmt.Println("恢复之后从这里继续执行")
	}()

	panic("Boom")
	fmt.Println("这里将不会执行下来")
}

image-20230202111829179

posted @ 2023-02-03 10:08  makalo  阅读(66)  评论(0编辑  收藏  举报