package mapstruct import ( "fmt" "reflect" "time" ) // HookFunc 定义字段转换钩子函数类型 type HookFunc func(reflect.Value, reflect.StructField) (any, error) // StringHookFunc 定义字符串到值的转换钩子函数类型 type StringHookFunc func(string, reflect.StructField) (any, error) // Options 包含所有转换选项 type Options struct { TagName string // 使用的结构体标签名称 TypeHooks map[reflect.Type]HookFunc // 类型级别的钩子 StringTypeHooks map[reflect.Type]StringHookFunc // 字符串到类型的钩子 FieldHooks map[string]HookFunc // 字段级别的钩子 } // Option 是配置选项的函数类型 type Option func(*Options) // WithTagName 设置结构体标签名称 func WithTagName(name string) Option { return func(o *Options) { o.TagName = name } } // WithTypeHook 添加类型级别的转换钩子 func WithTypeHook(typ reflect.Type, hook HookFunc) Option { return func(o *Options) { if o.TypeHooks == nil { o.TypeHooks = make(map[reflect.Type]HookFunc) } o.TypeHooks[typ] = hook } } // WithStringTypeHook 添加字符串到类型的转换钩子 func WithStringTypeHook(typ reflect.Type, hook StringHookFunc) Option { return func(o *Options) { if o.StringTypeHooks == nil { o.StringTypeHooks = make(map[reflect.Type]StringHookFunc) } o.StringTypeHooks[typ] = hook } } // WithFieldHook 添加字段级别的转换钩子 func WithFieldHook(fieldName string, hook HookFunc) Option { return func(o *Options) { if o.FieldHooks == nil { o.FieldHooks = make(map[string]HookFunc) } o.FieldHooks[fieldName] = hook } } //// WithStringFieldHook 添加字段级别的字符串转换钩子 //func WithStringFieldHook(fieldName string, hook StringHookFunc) Option { // return func(o *Options) { // if o.FieldHooks == nil { // o.FieldHooks = make(map[string]HookFunc) // } // // 适配器:将StringHookFunc转换为HookFunc // o.FieldHooks[fieldName] = func(v reflect.Value, f reflect.StructField) (any, error) { // if v.Kind() != reflect.String { // return nil, nil // } // return hook(v.String(), f) // } // } //} // defaultOptions 返回默认配置选项 func defaultOptions() *Options { opts := &Options{ TagName: "json", // 默认使用json标签 } // 注册默认的时间类型钩子 WithStringTypeHook(reflect.TypeOf(time.Time{}), func(value string, _ reflect.StructField) (any, error) { // 尝试多种常见时间格式 formats := []string{ "2006-01-02 15:04:05", // 标准格式 "2006-01-02", // 仅日期 time.RFC3339, // ISO8601格式 "2006/01/02 15:04:05", // 斜杠分隔 "2006/01/02", // 斜杠分隔仅日期 "02-Jan-2006", // 英文月份缩写 } for _, layout := range formats { if t, err := time.Parse(layout, value); err == nil { return t, nil } } return nil, fmt.Errorf("无法解析时间字符串: %s", value) })(opts) return opts }