public.go 3.8 KB

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