public.go 3.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172
  1. package fserr
  2. import (
  3. "errors"
  4. "fmt"
  5. "strings"
  6. )
  7. // New 创建新的错误,支持格式化占位符
  8. func New(format string, args ...any) error {
  9. msg := format
  10. if len(args) > 0 {
  11. msg = fmt.Sprintf(format, args...)
  12. }
  13. return &fundamental{
  14. msg: msg,
  15. stack: callers(),
  16. }
  17. }
  18. // Wrap 包装已有错误,支持格式化占位符
  19. func Wrap(err error, format string, args ...any) error {
  20. if err == nil {
  21. return nil
  22. }
  23. if len(strings.TrimSpace(format)) == 0 {
  24. return err
  25. }
  26. msg := format
  27. if len(args) > 0 {
  28. msg = fmt.Sprintf(format, args...)
  29. }
  30. return &withMessage{
  31. cause: wrapStack(err),
  32. msg: msg,
  33. }
  34. }
  35. // WithCode 创建带有错误码的error,支持格式化占位符
  36. // 使用option可以替换其中信息
  37. func WithCode[T codeType](err error, businessCode T, options ...Option) error {
  38. code := getCode(serviceCode + int(businessCode))
  39. ret := &withCode{
  40. cause: wrapStack(err),
  41. Msg: code.Message,
  42. HttpCode: code.HttpCode,
  43. BusinessCode: code.BusinessCode,
  44. }
  45. for _, option := range options {
  46. option(ret)
  47. }
  48. if err == nil {
  49. return &withStack{
  50. error: ret,
  51. stack: callers(),
  52. }
  53. }
  54. return ret
  55. }
  56. func WithStack(err error) error {
  57. return &withStack{
  58. error: err,
  59. stack: callers(),
  60. }
  61. }
  62. // UnWrap 获取包装过的error
  63. // 若error1使用 Wrap 包装后产出错误error2
  64. // 当使用 UmWrap 后,返回的是error1
  65. func UnWrap(err error) error {
  66. type causer interface {
  67. Cause() error
  68. }
  69. for err != nil {
  70. cause, ok := err.(causer)
  71. if !ok {
  72. break
  73. }
  74. err = cause.Cause()
  75. }
  76. return err
  77. }
  78. // Is 判断err是否是target类型
  79. // 相比==判断错误,该方式会进行不断地类似于 UmWrap 的操作,
  80. // 将 UmWrap 后的错误进行比较
  81. func Is(err, target error) bool {
  82. return errors.Is(err, target)
  83. }
  84. // As 匹配最外层的与target类型相同的error,将其赋值给target
  85. func As(err error, target any) bool { return errors.As(err, target) }
  86. // ParseCode 将错误解析为错误码错误
  87. // 若err不是错误码错误,则包裹传递错误,其他信息为默认错误码信息
  88. // 若err为错误码错误,将其转换,将最外层错误信息作为最终错误信息返回
  89. // 若想得到原始的错误码错误,可以使用As方法
  90. func ParseCode(err error) *withCode {
  91. var target *withCode
  92. if !As(err, &target) {
  93. return &withCode{
  94. cause: nil,
  95. Msg: err.Error(),
  96. HttpCode: defaultErrCode.HttpCode,
  97. BusinessCode: serviceCode,
  98. }
  99. }
  100. return &withCode{
  101. cause: target.cause,
  102. Msg: outerMsg(err),
  103. HttpCode: target.HttpCode,
  104. BusinessCode: target.BusinessCode,
  105. }
  106. }
  107. // IsCode 判断某个错误是否为某个错误码
  108. func IsCode[T codeType](err error, code T) bool {
  109. var target *withCode
  110. if !As(err, &target) {
  111. return false
  112. }
  113. return target.BusinessCode == serviceCode+int(code)
  114. }
  115. // SetAppCode 设置服务错误码
  116. // 模块码、模块错误码一共四位,指定应用码将拼接在前
  117. // 例如应用码位101,模块码为1,模块错误码为21,那么最终业务错误码为:1010121
  118. func SetAppCode[T codeType](code T) {
  119. serviceCode = int(code) * 10000
  120. }
  121. // outerMsg 获取最外层的错误信息
  122. func outerMsg(err error) string {
  123. if err == nil {
  124. return ""
  125. }
  126. if e, ok := err.(*withCode); ok {
  127. return e.Msg
  128. }
  129. if e, ok := err.(*withMessage); ok {
  130. return e.msg
  131. }
  132. if e, ok := err.(*withStack); ok {
  133. return outerMsg(e.error)
  134. }
  135. return err.Error()
  136. }
  137. func wrapStack(err error) error {
  138. if _, ok := err.(*fundamental); ok {
  139. return err
  140. }
  141. if _, ok := err.(*withCode); ok {
  142. return err
  143. }
  144. if _, ok := err.(*withMessage); ok {
  145. return err
  146. }
  147. if _, ok := err.(*withStack); ok {
  148. return err
  149. }
  150. return &withStack{
  151. error: err,
  152. stack: callers(),
  153. }
  154. }