聊聊golang的error增强

335 阅读1分钟

本文主要研究一下golang的error增强

Errors in Go 1.13

golang的1.13版本对error进行了增强,主要是

  • 引入了Unwrap方法
  • 增加Is和As方法
  • fmt.Errorf支持%w来包装error

实例

package main

import (
	"errors"
	"fmt"
	"os"
)

var DemoErr = errors.New("test error stack")

// https://itnext.io/golang-error-handling-best-practice-a36f47b0b94c
func main() {
	if err := methodA(false); err != nil {
		fmt.Printf("%+v\n", err)
	}

	if err := methodA(true); err != nil {
		fmt.Printf("%+v\n", err)
		fmt.Printf("%+v\n", errors.Unwrap(err))
		fmt.Printf("%+v\n", errors.Unwrap(errors.Unwrap(err)))

		fmt.Println("errors.Is(err, DemoErr)=", errors.Is(err, DemoErr))
		fmt.Println("errors.As(err, &DemoErr)=", errors.As(err, &DemoErr))

		var pe *os.PathError
		fmt.Println("errors.Is(err, pe)=", errors.Is(err, pe))
		fmt.Println("errors.As(err, &pe)=", errors.As(err, &pe))
	}
}

func methodA(wrap bool) error {
	if err := methodB(wrap); err != nil {
		if wrap {
			return fmt.Errorf("methodA call methodB error: %w", err)
		}
		return err
	}
	return nil
}

func methodB(wrap bool) error {
	if err := methodC(); err != nil {
		if wrap {
			return fmt.Errorf("methodB call methodC error: %w", err)
		}
		return err
	}
	return nil
}

func methodC() error {
	return DemoErr
}

输出

test error stack
methodA call methodB error: methodB call methodC error: test error stack
methodB call methodC error: test error stack
test error stack
errors.Is(err, DemoErr)= true
errors.As(err, &DemoErr)= true
errors.Is(err, pe)= false
errors.As(err, &pe)= false

小结

  • wrap对error进行了包装,不过没有包含堆栈
  • Is会挨个unwrap去对error进行判断errors.Is function behaves like a comparison to a sentinel error
  • As类似类型断言 errors.As function behaves like a type assertion

doc