完善错误码的用法

This commit is contained in:
yun
2026-07-22 00:05:37 +08:00
parent 8eaa8a6933
commit 4e81b83ab6
6 changed files with 620 additions and 211 deletions
+108 -61
View File
@@ -2,95 +2,142 @@ package errorx
import (
"context"
"errors"
"github.com/yuninks/langx"
)
// Key生成错误信息
type ErrorInterface interface {
Copy() ErrorInterface // 复制一个新的错误信息
Error() string // 实现error接口&获取翻译后的错误信息
GetCode() int // 获取翻译后的Code
GetKey() string // 获取原Key值
GetFormat() map[string]string // 获取附加数据
SetFormat(format map[string]string) // 设置附加数据
SetCtx(ctxHttp context.Context) // 设置上下文
SetLang(lang string) // 设置语言
SetFormatKV(key, value string) // 设置附加数据键值对
// ErrorInfo 是对外暴露的错误信息接口,语义精简、不可变。
type ErrorInfo interface {
error
Code() int
Key() string
Format() map[string]string
}
type defaultError struct {
// langError 是不可变的运行时错误实例,并发安全。
// 通过 With* 方法派生新实例,永远不会修改自身。
type langError struct {
ctx context.Context
key string
format map[string]string
}
func (l *defaultError) Copy() ErrorInterface {
return &defaultError{
ctx: l.ctx,
key: l.key,
format: l.format,
// ---- 实现 error 接口 -----------------------------------------------
func (e *langError) Error() string {
return langx.GetFormat(langx.GetCtxLang(e.ctx), e.key, e.format)
}
// ---- 实现 ErrorInfo 接口 --------------------------------------------
func (e *langError) Code() int { return langx.GetCode(e.key) }
func (e *langError) Key() string { return e.key }
func (e *langError) Format() map[string]string {
if len(e.format) == 0 {
return nil
}
return e.copyFormat()
}
func (e *defaultError) SetFormat(format map[string]string) {
e.format = format
// ---- 不可变派生方法(返回新实例,不修改原值)------------------------
// WithCtx 派生一个携带新上下文的错误实例。
func (e *langError) WithCtx(ctx context.Context) *langError {
return &langError{ctx: ctx, key: e.key, format: e.copyFormat()}
}
func (l *defaultError) SetFormatKV(key, value string) {
if l.format == nil {
l.format = make(map[string]string)
// WithLang 派生一个指定语言的错误实例。
func (e *langError) WithLang(lang string) *langError {
return &langError{ctx: langx.SetCtxLang(e.ctx, lang), key: e.key, format: e.copyFormat()}
}
// WithKV 派生一个添加单个占位符键值对的错误实例。
func (e *langError) WithKV(k, v string) *langError {
newFmt := e.copyFormat()
if newFmt == nil {
newFmt = make(map[string]string)
}
l.format[key] = value
newFmt[k] = v
return &langError{ctx: e.ctx, key: e.key, format: newFmt}
}
func (e *defaultError) SetCtx(ctxHttp context.Context) {
e.ctx = ctxHttp
}
func (l *defaultError) Error() string {
errLang := langx.GetCtxLang(l.ctx)
return langx.GetFormat(errLang, l.key, l.format)
}
func (e *defaultError) GetCode() int {
return langx.GetCode(e.key)
}
func (e *defaultError) GetKey() string {
return e.key
}
func (e *defaultError) GetFormat() map[string]string {
if e.format == nil {
e.format = make(map[string]string)
// WithMap 派生一个批量添加占位符键值对的错误实例(新 map 完全替换)。
func (e *langError) WithMap(m map[string]string) *langError {
newFmt := make(map[string]string, len(m))
for k, v := range m {
newFmt[k] = v
}
return e.format
return &langError{ctx: e.ctx, key: e.key, format: newFmt}
}
func (e *defaultError) SetLang(lang string) {
e.ctx = langx.SetCtxLang(e.ctx, lang)
}
// ---- 内部工具 --------------------------------------------------------
func NewErrorf(ctx context.Context, key string, format map[string]string) error {
return &defaultError{
ctx: ctx,
key: key,
format: format,
func (e *langError) copyFormat() map[string]string {
if len(e.format) == 0 {
return nil
}
dst := make(map[string]string, len(e.format))
for k, v := range e.format {
dst[k] = v
}
return dst
}
func NewError(ctx context.Context, key string) error {
return &defaultError{
ctx: ctx,
key: key,
func copyMapString(src map[string]string) map[string]string {
if len(src) == 0 {
return nil
}
dst := make(map[string]string, len(src))
for k, v := range src {
dst[k] = v
}
return dst
}
func NewStruct(ctx context.Context, key string, format map[string]string) ErrorInterface {
return &defaultError{
ctx: ctx,
key: key,
format: format,
// ---- 构造函数 --------------------------------------------------------
// NewError 创建一个携带 ctx 的运行时错误。
func NewError(ctx context.Context, key string) *langError {
return &langError{ctx: ctx, key: key}
}
// NewErrorf 创建一个携带占位符键值对的运行时错误。
func NewErrorf(ctx context.Context, key string, kv map[string]string) *langError {
return &langError{ctx: ctx, key: key, format: copyMapString(kv)}
}
// ---- 辅助函数,简化 error → ErrorInfo 提取 ---------------------------
// As 从 error 链中提取 *langError,失败返回 false。
func As(err error) (*langError, bool) {
var e *langError
ok := errors.As(err, &e)
return e, ok
}
// CodeFrom 从 error 中获取错误码;若不是 langError 则返回 -1。
func CodeFrom(err error) int {
if e, ok := As(err); ok {
return e.Code()
}
return -1
}
// KeyFrom 从 error 中获取 Key;若不是 langError 则返回空串。
func KeyFrom(err error) string {
if e, ok := As(err); ok {
return e.Key()
}
return ""
}
// FormatFrom 从 error 中获取占位符键值对(深拷贝);若不是 langError 则返回 nil。
func FormatFrom(err error) map[string]string {
if e, ok := As(err); ok {
return e.Format()
}
return nil
}