type convert
This commit is contained in:
106
copier.go
106
copier.go
@@ -26,10 +26,10 @@ func copy(dst, src any, opt *options) error {
|
|||||||
return ErrInvalidCopyDestination
|
return ErrInvalidCopyDestination
|
||||||
}
|
}
|
||||||
|
|
||||||
return deepCopy(dstValue, srcValue, 0, opt)
|
return deepCopy(dstValue, srcValue, 0, "", opt)
|
||||||
}
|
}
|
||||||
|
|
||||||
func deepCopy(dst, src reflect.Value, depth int, opt *options) error {
|
func deepCopy(dst, src reflect.Value, depth int, fieldName string, opt *options) error {
|
||||||
if src.IsZero() {
|
if src.IsZero() {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
@@ -42,20 +42,20 @@ func deepCopy(dst, src reflect.Value, depth int, opt *options) error {
|
|||||||
switch src.Kind() {
|
switch src.Kind() {
|
||||||
case reflect.Slice, reflect.Array:
|
case reflect.Slice, reflect.Array:
|
||||||
// slice -> slice
|
// slice -> slice
|
||||||
return copySlice(dst, src, depth, opt)
|
return copySlice(dst, src, depth, fieldName, opt)
|
||||||
case reflect.Map:
|
case reflect.Map:
|
||||||
switch dst.Kind() {
|
switch dst.Kind() {
|
||||||
case reflect.Map:
|
case reflect.Map:
|
||||||
// map -> map
|
// map -> map
|
||||||
return copyMap(dst, src, depth, opt)
|
return copyMap(dst, src, depth, fieldName, opt)
|
||||||
case reflect.Struct:
|
case reflect.Struct:
|
||||||
// map -> struct
|
// map -> struct
|
||||||
return copyMap2Struct(dst, src, depth, opt)
|
return copyMap2Struct(dst, src, depth, fieldName, opt)
|
||||||
case reflect.Pointer:
|
case reflect.Pointer:
|
||||||
elemType := dst.Type().Elem()
|
elemType := dst.Type().Elem()
|
||||||
newPtr := reflect.New(elemType)
|
newPtr := reflect.New(elemType)
|
||||||
|
|
||||||
if err := deepCopy(newPtr.Elem(), src, depth+1, opt); err != nil {
|
if err := deepCopy(newPtr.Elem(), src, depth+1, fieldName, opt); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -68,12 +68,12 @@ func deepCopy(dst, src reflect.Value, depth int, opt *options) error {
|
|||||||
switch dst.Kind() {
|
switch dst.Kind() {
|
||||||
case reflect.Map:
|
case reflect.Map:
|
||||||
// struct -> map
|
// struct -> map
|
||||||
return copyStruct2Map(dst, src, depth, opt)
|
return copyStruct2Map(dst, src, depth, fieldName, opt)
|
||||||
case reflect.Struct:
|
case reflect.Struct:
|
||||||
// struct -> struct
|
// struct -> struct
|
||||||
return copyStruct(dst, src, depth, opt)
|
return copyStruct(dst, src, depth, opt)
|
||||||
default:
|
default:
|
||||||
return ErrNotSupported
|
return set(dst, src, fieldName, opt)
|
||||||
}
|
}
|
||||||
|
|
||||||
case reflect.Func:
|
case reflect.Func:
|
||||||
@@ -98,7 +98,7 @@ func deepCopy(dst, src reflect.Value, depth int, opt *options) error {
|
|||||||
dst = dst.Elem()
|
dst = dst.Elem()
|
||||||
}
|
}
|
||||||
|
|
||||||
return deepCopy(dst, src, depth, opt)
|
return deepCopy(dst, src, depth, fieldName, opt)
|
||||||
|
|
||||||
case reflect.Interface:
|
case reflect.Interface:
|
||||||
if src.IsNil() {
|
if src.IsNil() {
|
||||||
@@ -106,13 +106,13 @@ func deepCopy(dst, src reflect.Value, depth int, opt *options) error {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if src.Kind() != dst.Kind() {
|
if src.Kind() != dst.Kind() {
|
||||||
return set(dst, src)
|
return set(dst, src, fieldName, opt)
|
||||||
}
|
}
|
||||||
|
|
||||||
src = src.Elem()
|
src = src.Elem()
|
||||||
newDst := reflect.New(src.Type().Elem())
|
newDst := reflect.New(src.Type().Elem())
|
||||||
|
|
||||||
if err := deepCopy(newDst, src, depth, opt); err != nil {
|
if err := deepCopy(newDst, src, depth, fieldName, opt); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -121,11 +121,11 @@ func deepCopy(dst, src reflect.Value, depth int, opt *options) error {
|
|||||||
case reflect.Chan:
|
case reflect.Chan:
|
||||||
return ErrNotSupported
|
return ErrNotSupported
|
||||||
default:
|
default:
|
||||||
return set(dst, src)
|
return set(dst, src, fieldName, opt)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func copyStruct2Map(dst, src reflect.Value, depth int, opt *options) error {
|
func copyStruct2Map(dst, src reflect.Value, depth int, fieldName string, opt *options) error {
|
||||||
for i, n := 0, src.NumField(); i < n; i++ {
|
for i, n := 0, src.NumField(); i < n; i++ {
|
||||||
sf := src.Type().Field(i)
|
sf := src.Type().Field(i)
|
||||||
if sf.PkgPath != "" && !sf.Anonymous {
|
if sf.PkgPath != "" && !sf.Anonymous {
|
||||||
@@ -135,7 +135,7 @@ func copyStruct2Map(dst, src reflect.Value, depth int, opt *options) error {
|
|||||||
if sf.Anonymous {
|
if sf.Anonymous {
|
||||||
switch sf.Type.Kind() {
|
switch sf.Type.Kind() {
|
||||||
case reflect.Struct, reflect.Pointer:
|
case reflect.Struct, reflect.Pointer:
|
||||||
if err := deepCopy(dst, src.Field(i), depth+1, opt); err != nil {
|
if err := deepCopy(dst, src.Field(i), depth+1, fieldName, opt); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -160,7 +160,7 @@ func copyStruct2Map(dst, src reflect.Value, depth int, opt *options) error {
|
|||||||
var newDst = reflect.ValueOf(make(map[string]any))
|
var newDst = reflect.ValueOf(make(map[string]any))
|
||||||
sField = indirect(sField)
|
sField = indirect(sField)
|
||||||
|
|
||||||
if err := deepCopy(newDst, sField, depth+1, opt); err != nil {
|
if err := deepCopy(newDst, sField, depth+1, name, opt); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -173,7 +173,7 @@ func copyStruct2Map(dst, src reflect.Value, depth int, opt *options) error {
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func copyMap2Struct(dst, src reflect.Value, depth int, opt *options) error {
|
func copyMap2Struct(dst, src reflect.Value, depth int, _ string, opt *options) error {
|
||||||
// 循环结构,然后从map取值
|
// 循环结构,然后从map取值
|
||||||
typ := dst.Type()
|
typ := dst.Type()
|
||||||
for i := 0; i < dst.NumField(); i++ {
|
for i := 0; i < dst.NumField(); i++ {
|
||||||
@@ -184,12 +184,12 @@ func copyMap2Struct(dst, src reflect.Value, depth int, opt *options) error {
|
|||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
fieldName := getFieldName(sf)
|
name := getFieldName(sf)
|
||||||
if fieldName == "-" {
|
if name == "-" {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
mapValue := src.MapIndex(reflect.ValueOf(fieldName))
|
mapValue := src.MapIndex(reflect.ValueOf(name))
|
||||||
if !mapValue.IsValid() {
|
if !mapValue.IsValid() {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
@@ -199,11 +199,11 @@ func copyMap2Struct(dst, src reflect.Value, depth int, opt *options) error {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if mapValue.Kind() == reflect.Map || mapValue.Kind() == reflect.Array || mapValue.Kind() == reflect.Slice {
|
if mapValue.Kind() == reflect.Map || mapValue.Kind() == reflect.Array || mapValue.Kind() == reflect.Slice {
|
||||||
if err := deepCopy(field, mapValue, depth+1, opt); err != nil {
|
if err := deepCopy(field, mapValue, depth+1, name, opt); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
if err := set(field, mapValue); err != nil {
|
if err := set(field, mapValue, name, opt); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -212,7 +212,7 @@ func copyMap2Struct(dst, src reflect.Value, depth int, opt *options) error {
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func copyMap(dst, src reflect.Value, depth int, opt *options) error {
|
func copyMap(dst, src reflect.Value, depth int, fieldName string, opt *options) error {
|
||||||
if dst.IsNil() {
|
if dst.IsNil() {
|
||||||
dst.Set(reflect.MakeMapWithSize(dst.Type(), src.Len()))
|
dst.Set(reflect.MakeMapWithSize(dst.Type(), src.Len()))
|
||||||
}
|
}
|
||||||
@@ -224,6 +224,15 @@ func copyMap(dst, src reflect.Value, depth int, opt *options) error {
|
|||||||
key := iter.Key()
|
key := iter.Key()
|
||||||
value := iter.Value()
|
value := iter.Value()
|
||||||
|
|
||||||
|
if name, ok := key.Interface().(string); ok {
|
||||||
|
fieldName = opt.NameConvert(name)
|
||||||
|
key = reflect.ValueOf(fieldName)
|
||||||
|
}
|
||||||
|
|
||||||
|
if opt.ignoreEmpty && value.IsZero() {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
var copitedValue reflect.Value
|
var copitedValue reflect.Value
|
||||||
switch dstType.Elem().Kind() {
|
switch dstType.Elem().Kind() {
|
||||||
case reflect.Interface:
|
case reflect.Interface:
|
||||||
@@ -234,12 +243,12 @@ func copyMap(dst, src reflect.Value, depth int, opt *options) error {
|
|||||||
copitedValue = reflect.New(value.Type()).Elem()
|
copitedValue = reflect.New(value.Type()).Elem()
|
||||||
}
|
}
|
||||||
|
|
||||||
set(copitedValue, value)
|
set(copitedValue, value, fieldName, opt)
|
||||||
default:
|
default:
|
||||||
copitedValue = reflect.New(dstType.Elem()).Elem()
|
copitedValue = reflect.New(dstType.Elem()).Elem()
|
||||||
}
|
}
|
||||||
|
|
||||||
if err := deepCopy(copitedValue, value, depth+1, opt); err != nil {
|
if err := deepCopy(copitedValue, value, depth+1, fieldName, opt); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -249,7 +258,7 @@ func copyMap(dst, src reflect.Value, depth int, opt *options) error {
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func copySlice(dst, src reflect.Value, depth int, opt *options) error {
|
func copySlice(dst, src reflect.Value, depth int, fieldName string, opt *options) error {
|
||||||
len := src.Len()
|
len := src.Len()
|
||||||
if dst.Len() > 0 && dst.Len() < src.Len() {
|
if dst.Len() > 0 && dst.Len() < src.Len() {
|
||||||
len = dst.Len()
|
len = dst.Len()
|
||||||
@@ -262,7 +271,7 @@ func copySlice(dst, src reflect.Value, depth int, opt *options) error {
|
|||||||
}
|
}
|
||||||
|
|
||||||
for i := 0; i < len; i++ {
|
for i := 0; i < len; i++ {
|
||||||
if err := deepCopy(dst.Index(i), src.Index(i), depth, opt); err != nil {
|
if err := deepCopy(dst.Index(i), src.Index(i), depth, fieldName, opt); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -302,14 +311,14 @@ func copyStruct(dst, src reflect.Value, depth int, opt *options) error {
|
|||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
if err := deepCopy(dstValue, sField, depth+1, opt); err != nil {
|
if err := deepCopy(dstValue, sField, depth+1, name, opt); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func set(dst, src reflect.Value) error {
|
func set(dst, src reflect.Value, fieldName string, opt *options) error {
|
||||||
if !src.IsValid() {
|
if !src.IsValid() {
|
||||||
return ErrInvalidCopyFrom
|
return ErrInvalidCopyFrom
|
||||||
}
|
}
|
||||||
@@ -318,6 +327,12 @@ func set(dst, src reflect.Value) error {
|
|||||||
src = src.Elem()
|
src = src.Elem()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if ok, err := lookupAndCopyWithConverter(dst, src, fieldName, opt); err != nil {
|
||||||
|
return err
|
||||||
|
} else if ok {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
if dst.Kind() == reflect.Pointer {
|
if dst.Kind() == reflect.Pointer {
|
||||||
if dst.IsNil() {
|
if dst.IsNil() {
|
||||||
if !dst.CanSet() {
|
if !dst.CanSet() {
|
||||||
@@ -404,6 +419,41 @@ func set(dst, src reflect.Value) error {
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func lookupAndCopyWithConverter(dst, src reflect.Value, fieldName string, opt *options) (bool, error) {
|
||||||
|
if cnv, ok := opt.convertByName[fieldName]; ok {
|
||||||
|
return convert(dst, src, cnv)
|
||||||
|
}
|
||||||
|
|
||||||
|
if len(opt.converters) > 0 {
|
||||||
|
pair := converterPair{
|
||||||
|
SrcType: src.Type(),
|
||||||
|
DstType: dst.Type(),
|
||||||
|
}
|
||||||
|
|
||||||
|
if cnv, ok := opt.converters[pair]; ok {
|
||||||
|
return convert(dst, src, cnv)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return false, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func convert(dst, src reflect.Value, fn convertFunc) (bool, error) {
|
||||||
|
result, err := fn(src.Interface())
|
||||||
|
if err != nil {
|
||||||
|
return false, err
|
||||||
|
}
|
||||||
|
|
||||||
|
if result != nil {
|
||||||
|
dst.Set(reflect.ValueOf(result))
|
||||||
|
} else {
|
||||||
|
dst.Set(reflect.Zero(dst.Type()))
|
||||||
|
}
|
||||||
|
|
||||||
|
return true, nil
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
func getFieldName(field reflect.StructField) string {
|
func getFieldName(field reflect.StructField) string {
|
||||||
if tag := field.Tag.Get("json"); tag != "" {
|
if tag := field.Tag.Get("json"); tag != "" {
|
||||||
if commaIndex := strings.Index(tag, ","); commaIndex != -1 {
|
if commaIndex := strings.Index(tag, ","); commaIndex != -1 {
|
||||||
|
|||||||
@@ -10,23 +10,32 @@ import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
func TestCopyMap(t *testing.T) {
|
func TestCopyMap(t *testing.T) {
|
||||||
type person struct {
|
|
||||||
Name string
|
|
||||||
Age int
|
|
||||||
}
|
|
||||||
|
|
||||||
src := map[string]any{
|
src := map[string]any{
|
||||||
"John": person{
|
"name": "Alice",
|
||||||
Name: "John",
|
"age": 25,
|
||||||
Age: 30,
|
"height": 165.5,
|
||||||
|
"is_student": true,
|
||||||
|
"birthday": "1998-05-15T06:00:00Z",
|
||||||
|
"tags": []any{"developer", "golang", "backend"},
|
||||||
|
"scores": []any{95, 88, 92},
|
||||||
|
"address": map[string]any{
|
||||||
|
"street": "123 Main St",
|
||||||
|
"city": "Beijing",
|
||||||
|
"country": "China",
|
||||||
},
|
},
|
||||||
|
"metadata": map[string]any{
|
||||||
|
"department": "Engineering",
|
||||||
|
"level": 3,
|
||||||
|
"projects": []any{"projectA", "projectB"},
|
||||||
|
},
|
||||||
|
"ptr_field": "pointer value",
|
||||||
}
|
}
|
||||||
|
|
||||||
dst := map[string]person{}
|
dst := map[string]any{}
|
||||||
|
|
||||||
assert.NoError(t, Copy(&dst, src))
|
assert.NoError(t, Copy(&dst, src))
|
||||||
|
|
||||||
fmt.Println(src, dst)
|
// fmt.Println(src, dst)
|
||||||
|
|
||||||
fmt.Println(json.Struct2JsonIndent(dst))
|
fmt.Println(json.Struct2JsonIndent(dst))
|
||||||
}
|
}
|
||||||
@@ -43,6 +52,18 @@ func TestMapAnyCopy(t *testing.T) {
|
|||||||
fmt.Println(src, dst)
|
fmt.Println(src, dst)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestIntMapCopy(t *testing.T) {
|
||||||
|
src := map[int]string{
|
||||||
|
1: "department",
|
||||||
|
3: "level",
|
||||||
|
}
|
||||||
|
|
||||||
|
dst := map[int]any{}
|
||||||
|
assert.NoError(t, Copy(&dst, src))
|
||||||
|
|
||||||
|
fmt.Println(src, dst)
|
||||||
|
}
|
||||||
|
|
||||||
func TestDiffStructMapCopy(t *testing.T) {
|
func TestDiffStructMapCopy(t *testing.T) {
|
||||||
type person struct {
|
type person struct {
|
||||||
Name string
|
Name string
|
||||||
|
|||||||
@@ -3,6 +3,7 @@ package copier
|
|||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
"testing"
|
"testing"
|
||||||
|
"time"
|
||||||
|
|
||||||
"github.com/stretchr/testify/assert"
|
"github.com/stretchr/testify/assert"
|
||||||
)
|
)
|
||||||
@@ -44,6 +45,28 @@ func TestCopySameStruct(t *testing.T) {
|
|||||||
fmt.Println("src,dst:", src, dst)
|
fmt.Println("src,dst:", src, dst)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestCopyToNamedStruct(t *testing.T) {
|
||||||
|
type Person3 struct {
|
||||||
|
Name string `copier:"toname=Name2"`
|
||||||
|
Age int
|
||||||
|
}
|
||||||
|
|
||||||
|
type Person4 struct {
|
||||||
|
Name2 string
|
||||||
|
Age int
|
||||||
|
}
|
||||||
|
|
||||||
|
src := &Person3{
|
||||||
|
Name: "John",
|
||||||
|
Age: 30,
|
||||||
|
}
|
||||||
|
|
||||||
|
var dst Person4
|
||||||
|
|
||||||
|
assert.NoError(t, Copy(&dst, src))
|
||||||
|
t.Log("src,dst:", src, dst)
|
||||||
|
}
|
||||||
|
|
||||||
func TestCopyDiffStruct(t *testing.T) {
|
func TestCopyDiffStruct(t *testing.T) {
|
||||||
src := &Person{
|
src := &Person{
|
||||||
Name: "John",
|
Name: "John",
|
||||||
@@ -223,3 +246,27 @@ func TestAnonymousFields(t *testing.T) {
|
|||||||
})
|
})
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestTypeConvert(t *testing.T) {
|
||||||
|
type Book struct {
|
||||||
|
Name string
|
||||||
|
Date time.Time
|
||||||
|
}
|
||||||
|
|
||||||
|
type Book2 struct {
|
||||||
|
Name string
|
||||||
|
Date string
|
||||||
|
}
|
||||||
|
|
||||||
|
var src = Book{
|
||||||
|
Name: "Book1",
|
||||||
|
Date: time.Now(),
|
||||||
|
}
|
||||||
|
|
||||||
|
var dst Book2
|
||||||
|
|
||||||
|
assert.NoError(t, Copy(&dst, &src, WithTypeConvertByName("Date", func(src any) (dst any, err error) {
|
||||||
|
return src.(time.Time).Format("2006-01-02"), nil
|
||||||
|
})))
|
||||||
|
t.Log("src,dst:", src, dst)
|
||||||
|
}
|
||||||
|
|||||||
48
optiongs.go
48
optiongs.go
@@ -6,16 +6,18 @@ const (
|
|||||||
noDepthLimited = -1
|
noDepthLimited = -1
|
||||||
)
|
)
|
||||||
|
|
||||||
|
type convertFunc func(any) (any, error)
|
||||||
|
|
||||||
type options struct {
|
type options struct {
|
||||||
tagName string // 标签名
|
tagName string // 标签名
|
||||||
maxDepth int // 最大复制深度
|
maxDepth int // 最大复制深度
|
||||||
ignoreEmpty bool // 复制时忽略空字段
|
ignoreEmpty bool // 复制时忽略空字段
|
||||||
caseSensitive bool // 复制时大小写敏感
|
caseSensitive bool // 复制时大小写敏感
|
||||||
must bool // 只复制具有must标识的字段
|
must bool // 只复制具有must标识的字段
|
||||||
convertersByName map[string]TypeConverter // 根据名称处理的类型转换器
|
|
||||||
converters []TypeConverter // 根据源和目标类型处理的类型转换器
|
|
||||||
fieldNameMapping map[string]string // 字段名转映射
|
fieldNameMapping map[string]string // 字段名转映射
|
||||||
nameConverter func(string) string // 字段名转换器
|
nameConverter func(string) string // 字段名转换函数
|
||||||
|
converters map[converterPair]convertFunc // 根据源和目标类型处理的类型转换器v
|
||||||
|
convertByName map[string]convertFunc // 根据名称处理的类型转换器
|
||||||
}
|
}
|
||||||
|
|
||||||
type option func(*options)
|
type option func(*options)
|
||||||
@@ -27,16 +29,18 @@ type TypeConverter struct {
|
|||||||
Fn func(src any) (dst any, err error)
|
Fn func(src any) (dst any, err error)
|
||||||
}
|
}
|
||||||
|
|
||||||
type FieldNameConverter struct {
|
type converterPair struct {
|
||||||
SrcFieldName string
|
Name string
|
||||||
DstFieldName string
|
SrcType reflect.Type
|
||||||
|
DstType reflect.Type
|
||||||
}
|
}
|
||||||
|
|
||||||
func getOpt(opts ...option) *options {
|
func getOpt(opts ...option) *options {
|
||||||
opt := &options{
|
opt := &options{
|
||||||
maxDepth: noDepthLimited,
|
maxDepth: noDepthLimited,
|
||||||
tagName: defaultTag,
|
tagName: defaultTag,
|
||||||
convertersByName: make(map[string]TypeConverter),
|
convertByName: make(map[string]convertFunc),
|
||||||
|
converters: make(map[converterPair]convertFunc),
|
||||||
}
|
}
|
||||||
|
|
||||||
for _, o := range opts {
|
for _, o := range opts {
|
||||||
@@ -58,68 +62,74 @@ func (opt *options) NameConvert(name string) string {
|
|||||||
return name
|
return name
|
||||||
}
|
}
|
||||||
|
|
||||||
func (opt options) TypeConvert(value reflect.Value) (reflect.Value, bool) {
|
|
||||||
for _, c := range opt.converters {
|
|
||||||
_ = c
|
|
||||||
}
|
|
||||||
return value, false
|
|
||||||
}
|
|
||||||
|
|
||||||
func (opt *options) ExceedMaxDepth(depth int) bool {
|
func (opt *options) ExceedMaxDepth(depth int) bool {
|
||||||
return opt.maxDepth != noDepthLimited && depth > opt.maxDepth
|
return opt.maxDepth != noDepthLimited && depth > opt.maxDepth
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// WithMaxDepth 设置最大复制深度
|
||||||
func WithMaxDepth(depth int) option {
|
func WithMaxDepth(depth int) option {
|
||||||
return func(o *options) {
|
return func(o *options) {
|
||||||
o.maxDepth = depth
|
o.maxDepth = depth
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// WithIgnoreEmpty 复制时忽略空字段标识
|
||||||
func WithIgnoreEmpty() option {
|
func WithIgnoreEmpty() option {
|
||||||
return func(o *options) {
|
return func(o *options) {
|
||||||
o.ignoreEmpty = true
|
o.ignoreEmpty = true
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// WithCaseInsensitive 复制时大小写不敏感标识
|
||||||
func WithCaseSensitive() option {
|
func WithCaseSensitive() option {
|
||||||
return func(o *options) {
|
return func(o *options) {
|
||||||
o.caseSensitive = true
|
o.caseSensitive = true
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// WithMust 添加必须复制标识
|
||||||
func WithMust() option {
|
func WithMust() option {
|
||||||
return func(o *options) {
|
return func(o *options) {
|
||||||
o.must = true
|
o.must = true
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// WithNameConvertByName 添加根据名称处理的类型转换器
|
||||||
func WithTypeConvertByName(name string, f func(src any) (dst any, err error)) option {
|
func WithTypeConvertByName(name string, f func(src any) (dst any, err error)) option {
|
||||||
return func(o *options) {
|
return func(o *options) {
|
||||||
o.convertersByName[name] = TypeConverter{
|
o.convertByName[name] = f
|
||||||
FieldName: name,
|
|
||||||
Fn: f,
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// WithTypeConvert 添加根据源和目标类型处理的类型转换器
|
||||||
func WithConverters(converters ...TypeConverter) option {
|
func WithConverters(converters ...TypeConverter) option {
|
||||||
return func(o *options) {
|
return func(o *options) {
|
||||||
o.converters = converters
|
for i := range converters {
|
||||||
|
pair := converterPair{
|
||||||
|
SrcType: reflect.TypeOf(converters[i].SrcType),
|
||||||
|
DstType: reflect.TypeOf(converters[i].DstType),
|
||||||
|
}
|
||||||
|
|
||||||
|
o.converters[pair] = converters[i].Fn
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// WithNameMapping 添加字段名映射
|
||||||
func WithNameMapping(mappings map[string]string) option {
|
func WithNameMapping(mappings map[string]string) option {
|
||||||
return func(o *options) {
|
return func(o *options) {
|
||||||
o.fieldNameMapping = mappings
|
o.fieldNameMapping = mappings
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// WithNameConverter 添加字段名转换函数
|
||||||
func WithNameFn(fn func(string) string) option {
|
func WithNameFn(fn func(string) string) option {
|
||||||
return func(o *options) {
|
return func(o *options) {
|
||||||
o.nameConverter = fn
|
o.nameConverter = fn
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// WithTagName 添加标签名
|
||||||
func WithTagName(tagName string) option {
|
func WithTagName(tagName string) option {
|
||||||
return func(o *options) {
|
return func(o *options) {
|
||||||
o.tagName = tagName
|
o.tagName = tagName
|
||||||
|
|||||||
Reference in New Issue
Block a user