public.go 3.6 KB

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