108 lines
3.0 KiB
Go
108 lines
3.0 KiB
Go
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
|
||
}
|