golang 错误与异常处理

错误(error)

  • error是一个接口
    • 我们可以定义自己的错误类型来实现这个接口
type error interface {
	Error() string
}
  • 自定义错误值应该统一分组定义,而不是零散的分布在各个角落
    • 然后返回时直接返回这些新变量
// file error objectvar 
var (
        ErrEof = errors.New("EOF")
        ErrClosedPipe = errors.New("io: read/write on closed pipe")
)
// 多层包装错误
f() {
	if err := ff(); err != nil {
		return fmt.Errorf("f: %w", err)
	}	
}

// 解析错误
	err = errors.Unwrap(err)
  • 统一错误处理
func logPanics(f http.HandlerFunc) http.HandlerFunc {
	return func(w http.ResponseWriter, r *http.Request) {
		defer func() {
			if err := recover(); err != nil {
				log.Printf("[%v] caught panic: %v", r.RemoteAddr, err)
			}
			f(w, r)
		}()
	}
}

//使用
http.HandleFunc("/<path>", logPanics(func1))

异常(panic)

  • 异常的恢复(recover)必须写在defer函数中
    • 否则直接返回nil,并不会捕获异常
  • 一个子goroutine中发生panic会导致整个程序崩溃
    • 一个goroutine发生的异常只能被自己恢复
    • 每一个可能panic的goroutine都要加上异常恢复处理
  • panic表示发生了严重的错误,不应该被频繁使用
    • 但有时可以通过panic简化错误处理
      在这里插入图片描述
// 使用error的写法
func first() error {return nil}
func second() error {return nil}
func third() error {return nil}

func Do() error {
    var err error
    if err = first(); err == nil {
        if err = second(); err == nil {
            if err = third(); err == nil {
               return nil
            }
        }
    }
    return err
}

// 改为panic的写法

func Do2() (err error) {
    defer func(){
        if r:= recover() ; r!= nil{
            err = fmt.Errorf("Error: %+v", r)
        }
    }()
    first2()
    second2()
    third2()
    return
}
  • recover只有在defer中才会生效,且defer必须注册在panic前
  • 如果要在上层函数捕获下层函数的panic,则defer必须在下层函数调用前注册(定义)
func f() {
	defer func() {
		if err := recover(); err != nil {
			fmt.Println(err)
		}
	}()

	// 注意ff调用必须在defer之后
	ff()
}

func ff() {
	panic("panic in ff")

}
发布了161 篇原创文章 · 获赞 19 · 访问量 5万+

猜你喜欢

转载自blog.csdn.net/winter_wu_1998/article/details/101670307