123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172 |
- package fserr
- import (
- "errors"
- "fmt"
- "strconv"
- "strings"
- )
- // New 创建新的错误,支持格式化占位符
- func New(format string, args ...any) error {
- msg := format
- if len(args) > 0 {
- msg = fmt.Sprintf(format, args...)
- }
- return &fundamental{
- msg: msg,
- stack: callers(),
- }
- }
- // Wrap 包装已有错误,支持格式化占位符
- func Wrap(err error, format string, args ...any) error {
- if err == nil {
- return nil
- }
- msg := format
- if len(args) > 0 {
- msg = fmt.Sprintf(format, args...)
- }
- return &withMessage{
- cause: wrapStack(err),
- msg: msg,
- }
- }
- // WithCode 创建带有错误码的error,支持格式化占位符
- // 使用option可以替换其中信息
- func WithCode[T codeType](err error, businessCode T, options ...Option) error {
- code := getCode(serviceCode + int(businessCode))
- ret := &withCode{
- cause: wrapStack(err),
- Msg: code.Message,
- HttpCode: code.HttpCode,
- BusinessCode: code.BusinessCode,
- }
- for _, option := range options {
- option(ret)
- }
- if err == nil {
- return &withStack{
- error: ret,
- stack: callers(),
- }
- }
- return ret
- }
- // UnWrap 获取包装过的error
- // 若error1使用 Wrap 包装后产出错误error2
- // 当使用 UmWrap 后,返回的是error1
- func UnWrap(err error) error {
- type causer interface {
- Cause() error
- }
- for err != nil {
- cause, ok := err.(causer)
- if !ok {
- break
- }
- err = cause.Cause()
- }
- return err
- }
- // Is 判断err是否是target类型
- // 相比==判断错误,该方式会进行不断地类似于 UmWrap 的操作,
- // 将 UmWrap 后的错误进行比较
- func Is(err, target error) bool {
- return errors.Is(err, target)
- }
- // As 匹配最外层的与target类型相同的error,将其赋值给target
- func As(err error, target any) bool { return errors.As(err, target) }
- // ParseCode 将错误解析为错误码错误
- // 若err不是错误码错误,则包裹传递错误,其他信息为默认错误码信息
- // 若err为错误码错误,将其转换,将最外层错误信息作为最终错误信息返回
- // 若想得到原始的错误码错误,可以使用As方法
- func ParseCode(err error) *withCode {
- var target *withCode
- if !As(err, &target) {
- return &withCode{
- cause: nil,
- Msg: err.Error(),
- HttpCode: defaultErrCode.HttpCode,
- BusinessCode: serviceCode * 10000,
- }
- }
- return &withCode{
- cause: target.cause,
- Msg: outerMsg(err),
- HttpCode: target.HttpCode,
- BusinessCode: target.BusinessCode,
- }
- }
- // IsCode 判断某个错误是否为某个错误码
- func IsCode[T codeType](err error, code T) bool {
- var target *withCode
- if !As(err, &target) {
- return false
- }
- return target.BusinessCode == serviceCode+int(code)
- }
- // SetAppCode 设置服务错误码
- // 例如设置服务码为300000,用户不存在错误码为2001,
- // 那么最终业务错误码为302001
- func SetAppCode[T codeType](code T) {
- strCode := strconv.Itoa(int(code))
- if len(strCode) == 1 {
- strCode = "0" + strCode
- }
- c, err := strconv.ParseInt(strCode+strings.Repeat("0", 6-len(strCode)),
- 10, 64)
- if err != nil {
- panic(err)
- }
- serviceCode = int(c)
- }
- // outerMsg 获取最外层的错误信息
- func outerMsg(err error) string {
- if err == nil {
- return ""
- }
- if e, ok := err.(*withCode); ok {
- return e.Msg
- }
- if e, ok := err.(*withMessage); ok {
- return e.msg
- }
- if e, ok := err.(*withStack); ok {
- return outerMsg(e.error)
- }
- return err.Error()
- }
- func wrapStack(err error) error {
- if _, ok := err.(*fundamental); ok {
- return err
- }
- if _, ok := err.(*withCode); ok {
- return err
- }
- if _, ok := err.(*withMessage); ok {
- return err
- }
- if _, ok := err.(*withStack); ok {
- return err
- }
- return &withStack{
- error: err,
- stack: callers(),
- }
- }
|