Browse Source

Merge branch 'dev' into v1.1.0

yjp 4 months ago
parent
commit
b9f78f5f49

+ 0 - 12
framework/core/tag/assign/assign.go

@@ -28,18 +28,6 @@ func UseTag(from any, to any, onParsedFieldTagFunc OnParsedFieldTagCallback) err
 	fromElemValue := reflectutils.PointerValueElem(fromValue)
 	toElemValue := reflectutils.PointerValueElem(toValue)
 
-	for i := 0; i < toElemValue.NumField(); i++ {
-		toField := toElemValue.Field(i)
-		if !toField.IsValid() {
-			return errors.New("被赋值的结构存在无效字段")
-		}
-
-		// 初始化空值指针
-		if toField.Kind() == reflect.Ptr && toField.IsNil() {
-			toField.Set(reflect.New(toField.Type().Elem()))
-		}
-	}
-
 	err := parseTag(fromElemValue, &toElemValue, onParsedFieldTagFunc)
 	if err != nil {
 		return err

+ 6 - 7
framework/core/tag/assign/tag.go

@@ -52,16 +52,11 @@ func parseTag(fromElemValue reflect.Value, toElemValue *reflect.Value, onParsedF
 			continue
 		}
 
+		fromFieldElemValue := reflectutils.PointerValueElem(fromFieldValue)
 		if fromFieldValue.Kind() == reflect.Pointer && fromFieldValue.IsNil() {
-			if !fromFieldValue.CanSet() {
-				return errors.New("无法设置值,请检查是否传递的是非指针结构变量且字段为nil")
-			}
-
-			fromFieldValue.Set(reflect.New(fromField.Type.Elem()))
+			fromFieldElemValue = reflect.New(fromFieldValue.Type().Elem()).Elem()
 		}
 
-		fromFieldElemValue := reflectutils.PointerValueElem(fromFieldValue)
-
 		tagStr := fromField.Tag.Get(tagKey)
 
 		// 结构类型的字段上没有添加Tag, 先尝试直接按照字段赋值
@@ -98,6 +93,10 @@ func parseTag(fromElemValue reflect.Value, toElemValue *reflect.Value, onParsedF
 
 		toFieldElemValue := toFieldValue
 		if toFieldValue.Kind() == reflect.Pointer {
+			if fromFieldValue.Kind() == reflect.Pointer && fromFieldValue.IsNil() {
+				continue
+			}
+
 			if !toFieldValue.IsValid() {
 				continue
 			}

+ 166 - 2
framework/core/tag/assign/usage.go

@@ -3,6 +3,7 @@ package assign
 import (
 	"git.sxidc.com/go-tools/utils/reflectutils"
 	"git.sxidc.com/go-tools/utils/strutils"
+	"github.com/pkg/errors"
 	"reflect"
 	"strings"
 	"time"
@@ -43,12 +44,53 @@ func defaultCallback(fromFieldElemValue reflect.Value, toFieldElemValue reflect.
 		// 直接将整个结构进行字段赋值
 		fromAny = fromFieldElemValue.Interface()
 	case reflect.Slice:
-		if reflectutils.IsSliceValueOf(fromFieldElemValue, reflect.String) && toKind == reflect.String {
-			fromString := strings.Join(fromFieldElemValue.Interface().([]string), tag.JoinWith)
+		fromFieldElementElemType := reflectutils.PointerTypeElem(fromFieldElemValue.Type().Elem())
+
+		if fromFieldElementElemType.Kind() == reflect.String && toKind == reflect.String {
+			stringSlice := make([]string, 0)
+			for i := 0; i < fromFieldElemValue.Len(); i++ {
+				stringSlice = append(stringSlice, reflectutils.PointerValueElem(fromFieldElemValue.Index(i)).Interface().(string))
+			}
+
+			fromString := strings.Join(stringSlice, tag.JoinWith)
 			fromAny = trimFromString(fromString, tag)
 			break
 		}
 
+		if fromFieldElementElemType.Kind() == reflect.Struct &&
+			reflectutils.IsTypeTime(fromFieldElementElemType) &&
+			toFieldElemValue.Type().Kind() == reflect.Slice &&
+			reflectutils.PointerTypeElem(toFieldElemValue.Type().Elem()).Kind() == reflect.String {
+			stringSlice := make([]string, 0)
+
+			for i := 0; i < fromFieldElemValue.Len(); i++ {
+				fromString := reflectutils.PointerValueElem(fromFieldElemValue.Index(i)).Interface().(time.Time).Format(tag.TimeLayout)
+				stringSlice = append(stringSlice, trimFromString(fromString, tag))
+			}
+
+			fromAny = stringSlice
+			break
+		}
+
+		if fromFieldElementElemType.Kind() == reflect.String &&
+			toFieldElemValue.Type().Kind() == reflect.Slice &&
+			reflectutils.PointerTypeElem(toFieldElemValue.Type().Elem()).Kind() == reflect.Struct &&
+			reflectutils.IsTypeTime(reflectutils.PointerTypeElem(toFieldElemValue.Type().Elem())) {
+			timeSlice := make([]time.Time, 0)
+
+			for i := 0; i < fromFieldElemValue.Len(); i++ {
+				timeParsed, err := time.ParseInLocation(tag.TimeLayout, reflectutils.PointerValueElem(fromFieldElemValue.Index(i)).Interface().(string), time.Local)
+				if err != nil {
+					return err
+				}
+
+				timeSlice = append(timeSlice, timeParsed)
+			}
+
+			fromAny = timeSlice
+			break
+		}
+
 		fromAny = fromFieldElemValue.Interface()
 	case reflect.String:
 		fromString := fromFieldElemValue.String()
@@ -73,6 +115,15 @@ func defaultCallback(fromFieldElemValue reflect.Value, toFieldElemValue reflect.
 		fromAny = fromFieldElemValue.Interface()
 	}
 
+	err := assignTo(toKind, fromAny, toFieldElemValue)
+	if err != nil {
+		return err
+	}
+
+	return nil
+}
+
+func assignTo(toKind reflect.Kind, fromAny any, toFieldElemValue reflect.Value) error {
 	switch toKind {
 	case reflect.Int64:
 		return reflectutils.AssignInt64Value(fromAny, toFieldElemValue)
@@ -84,6 +135,8 @@ func defaultCallback(fromFieldElemValue reflect.Value, toFieldElemValue reflect.
 		return reflectutils.AssignBoolValue(fromAny, toFieldElemValue)
 	case reflect.String:
 		return reflectutils.AssignStringValue(fromAny, toFieldElemValue)
+	case reflect.Slice:
+		return assignSlice(fromAny, toFieldElemValue)
 	default:
 		toFieldElemValue.Set(reflect.ValueOf(fromAny))
 		return nil
@@ -105,3 +158,114 @@ func trimFromString(fromString string, tag *Tag) string {
 
 	return fromString
 }
+
+func assignSlice(fromAny any, toFieldElemValue reflect.Value) error {
+	fromElemValue := reflectutils.PointerValueElem(reflect.ValueOf(fromAny))
+
+	if fromElemValue.Kind() != reflect.Slice {
+		return errors.New("不支持的操作:试图将非slice类型字段赋值给slice类型字段")
+	}
+
+	if toFieldElemValue.Kind() != reflect.Slice {
+		return errors.New("不支持的操作:试图将slice类型字段赋值给非slice类型字段")
+	}
+
+	// 构造slice
+	sliceValue := reflect.MakeSlice(toFieldElemValue.Type(), 0, 0)
+
+	// 遍历from slice
+	for i := 0; i < fromElemValue.Len(); i++ {
+		// 获取from slice中元素的Value
+		fromElementValue := fromElemValue.Index(i)
+
+		// 获取from slice中元素的ElemValue
+		fromElementElemValue := reflectutils.PointerValueElem(fromElementValue)
+
+		// 获取from slice中元素是nil指针
+		if fromElementValue.Kind() == reflect.Pointer && fromElementValue.IsNil() {
+			fromElementElemValue = reflect.New(fromElementElemValue.Type()).Elem()
+		}
+
+		if fromElementElemValue.Kind() == reflect.Slice {
+			if toFieldElemValue.Type().Elem().Kind() != reflect.Slice {
+				return errors.New("不支持的操作:试图将slice类型字段赋值给非slice类型字段")
+			}
+
+			toSliceElementValue := reflect.MakeSlice(toFieldElemValue.Type().Elem(), 0, 0)
+			err := assignSlice(fromElementElemValue.Interface(), toSliceElementValue)
+			if err != nil {
+				return err
+			}
+
+			for j := 0; j < toSliceElementValue.Len(); j++ {
+				if toFieldElemValue.Type().Elem().Kind() == reflect.Pointer {
+					sliceValue = reflect.Append(sliceValue, toSliceElementValue.Index(i).Addr())
+				} else {
+					sliceValue = reflect.Append(sliceValue, toSliceElementValue.Index(i))
+				}
+			}
+
+			continue
+		}
+
+		var toElementElemValue reflect.Value
+
+		if toFieldElemValue.Type().Elem().Kind() == reflect.Pointer {
+			if toFieldElemValue.Type().Elem().Elem().Kind() == fromElementElemValue.Kind() &&
+				toFieldElemValue.Type().Elem().Elem().String() == fromElementElemValue.Type().String() {
+				toElementElemValue = fromElementElemValue
+			} else {
+				toElementElemValue = reflect.New(toFieldElemValue.Type().Elem().Elem()).Elem()
+			}
+		} else {
+			if toFieldElemValue.Type().Elem().Kind() == fromElementElemValue.Kind() &&
+				toFieldElemValue.Type().Elem().String() == fromElementElemValue.String() {
+				toElementElemValue = fromElementValue
+			} else {
+				toElementElemValue = reflect.New(toFieldElemValue.Type().Elem()).Elem()
+			}
+		}
+
+		if fromElementElemValue.Kind() == reflect.Struct {
+			if reflectutils.IsValueTime(fromElementElemValue) {
+				if !reflectutils.IsValueTime(toElementElemValue) {
+					return errors.New("无法从time.Time赋值到不是time.Time的结构")
+				}
+
+				if toElementElemValue.Type().Kind() == reflect.Pointer {
+					toElementElemValue.Set(fromElementElemValue.Addr())
+				} else {
+					toElementElemValue.Set(fromElementElemValue)
+				}
+			} else {
+				err := DefaultUsage(fromElementElemValue.Interface(), toElementElemValue.Addr().Interface())
+				if err != nil {
+					return err
+				}
+			}
+
+			if toFieldElemValue.Type().Elem().Kind() == reflect.Pointer {
+				sliceValue = reflect.Append(sliceValue, toElementElemValue.Addr())
+			} else {
+				sliceValue = reflect.Append(sliceValue, toElementElemValue)
+			}
+
+			continue
+		}
+
+		toElementKind := reflectutils.GroupValueKind(toElementElemValue)
+		err := assignTo(toElementKind, fromElementElemValue.Interface(), toElementElemValue)
+		if err != nil {
+			return err
+		}
+
+		if toFieldElemValue.Type().Elem().Kind() == reflect.Pointer {
+			sliceValue = reflect.Append(sliceValue, toElementElemValue.Addr())
+		} else {
+			sliceValue = reflect.Append(sliceValue, toElementElemValue)
+		}
+	}
+
+	toFieldElemValue.Set(sliceValue)
+	return nil
+}

+ 1132 - 169
test/assign_tag_test.go

@@ -11,81 +11,75 @@ import (
 )
 
 type AssignTagFrom struct {
-	StringField                  string              `assign:"toField:StringField"`
-	BoolField                    bool                `assign:"toField:BoolField"`
-	IntField                     int                 `assign:"toField:IntField"`
-	Int8Field                    int8                `assign:"toField:Int8Field"`
-	Int16Field                   int16               `assign:"toField:Int16Field"`
-	Int32Field                   int32               `assign:"toField:Int32Field"`
-	Int64Field                   int64               `assign:"toField:Int64Field"`
-	UintField                    uint                `assign:"toField:UintField"`
-	Uint8Field                   uint8               `assign:"toField:Uint8Field"`
-	Uint16Field                  uint16              `assign:"toField:Uint16Field"`
-	Uint32Field                  uint32              `assign:"toField:Uint32Field"`
-	Uint64Field                  uint64              `assign:"toField:Uint64Field"`
-	Float32Field                 float32             `assign:"toField:Float32Field"`
-	Float64Field                 float64             `assign:"toField:Float64Field"`
-	SliceField                   []string            `assign:"toField:SliceField"`
-	MapField                     map[string]string   `assign:"toField:MapField"`
-	ChanField                    chan any            `assign:"toField:ChanField"`
-	FuncField                    func() string       `assign:"toField:FuncField"`
-	StructField                  struct{ ID string } `assign:"toField:StructField"`
-	FromStringSliceToStringField []string            `assign:"toField:FromStringSliceToStringField"`
-	FromTimeToStringField        time.Time           `assign:"toField:FromTimeToStringField"`
-	FromTimeToTimeField          time.Time           `assign:"toField:FromTimeToTimeField"`
-	FromStringToTimeField        string              `assign:"toField:FromStringToTimeField"`
+	StringField           string              `assign:"toField:StringField"`
+	BoolField             bool                `assign:"toField:BoolField"`
+	IntField              int                 `assign:"toField:IntField"`
+	Int8Field             int8                `assign:"toField:Int8Field"`
+	Int16Field            int16               `assign:"toField:Int16Field"`
+	Int32Field            int32               `assign:"toField:Int32Field"`
+	Int64Field            int64               `assign:"toField:Int64Field"`
+	UintField             uint                `assign:"toField:UintField"`
+	Uint8Field            uint8               `assign:"toField:Uint8Field"`
+	Uint16Field           uint16              `assign:"toField:Uint16Field"`
+	Uint32Field           uint32              `assign:"toField:Uint32Field"`
+	Uint64Field           uint64              `assign:"toField:Uint64Field"`
+	Float32Field          float32             `assign:"toField:Float32Field"`
+	Float64Field          float64             `assign:"toField:Float64Field"`
+	MapField              map[string]string   `assign:"toField:MapField"`
+	ChanField             chan any            `assign:"toField:ChanField"`
+	FuncField             func() string       `assign:"toField:FuncField"`
+	StructField           struct{ ID string } `assign:"toField:StructField"`
+	FromTimeToStringField time.Time           `assign:"toField:FromTimeToStringField"`
+	FromTimeToTimeField   time.Time           `assign:"toField:FromTimeToTimeField"`
+	FromStringToTimeField string              `assign:"toField:FromStringToTimeField"`
 }
 
 type AssignTagFromPointerField struct {
-	StringField                  *string              `assign:"toField:StringField"`
-	BoolField                    *bool                `assign:"toField:BoolField"`
-	IntField                     *int                 `assign:"toField:IntField"`
-	Int8Field                    *int8                `assign:"toField:Int8Field"`
-	Int16Field                   *int16               `assign:"toField:Int16Field"`
-	Int32Field                   *int32               `assign:"toField:Int32Field"`
-	Int64Field                   *int64               `assign:"toField:Int64Field"`
-	UintField                    *uint                `assign:"toField:UintField"`
-	Uint8Field                   *uint8               `assign:"toField:Uint8Field"`
-	Uint16Field                  *uint16              `assign:"toField:Uint16Field"`
-	Uint32Field                  *uint32              `assign:"toField:Uint32Field"`
-	Uint64Field                  *uint64              `assign:"toField:Uint64Field"`
-	Float32Field                 *float32             `assign:"toField:Float32Field"`
-	Float64Field                 *float64             `assign:"toField:Float64Field"`
-	SliceField                   *[]string            `assign:"toField:SliceField"`
-	MapField                     *map[string]string   `assign:"toField:MapField"`
-	ChanField                    *chan any            `assign:"toField:ChanField"`
-	FuncField                    *func() string       `assign:"toField:FuncField"`
-	StructField                  *struct{ ID string } `assign:"toField:StructField"`
-	FromStringSliceToStringField *[]string            `assign:"toField:FromStringSliceToStringField"`
-	FromTimeToStringField        *time.Time           `assign:"toField:FromTimeToStringField"`
-	FromTimeToTimeField          *time.Time           `assign:"toField:FromTimeToTimeField"`
-	FromStringToTimeField        *string              `assign:"toField:FromStringToTimeField"`
+	StringField           *string              `assign:"toField:StringField"`
+	BoolField             *bool                `assign:"toField:BoolField"`
+	IntField              *int                 `assign:"toField:IntField"`
+	Int8Field             *int8                `assign:"toField:Int8Field"`
+	Int16Field            *int16               `assign:"toField:Int16Field"`
+	Int32Field            *int32               `assign:"toField:Int32Field"`
+	Int64Field            *int64               `assign:"toField:Int64Field"`
+	UintField             *uint                `assign:"toField:UintField"`
+	Uint8Field            *uint8               `assign:"toField:Uint8Field"`
+	Uint16Field           *uint16              `assign:"toField:Uint16Field"`
+	Uint32Field           *uint32              `assign:"toField:Uint32Field"`
+	Uint64Field           *uint64              `assign:"toField:Uint64Field"`
+	Float32Field          *float32             `assign:"toField:Float32Field"`
+	Float64Field          *float64             `assign:"toField:Float64Field"`
+	MapField              *map[string]string   `assign:"toField:MapField"`
+	ChanField             *chan any            `assign:"toField:ChanField"`
+	FuncField             *func() string       `assign:"toField:FuncField"`
+	StructField           *struct{ ID string } `assign:"toField:StructField"`
+	FromTimeToStringField *time.Time           `assign:"toField:FromTimeToStringField"`
+	FromTimeToTimeField   *time.Time           `assign:"toField:FromTimeToTimeField"`
+	FromStringToTimeField *string              `assign:"toField:FromStringToTimeField"`
 }
 
 type AssignTagTo struct {
-	StringField                  string
-	BoolField                    bool
-	IntField                     int
-	Int8Field                    int8
-	Int16Field                   int16
-	Int32Field                   int32
-	Int64Field                   int64
-	UintField                    uint
-	Uint8Field                   uint8
-	Uint16Field                  uint16
-	Uint32Field                  uint32
-	Uint64Field                  uint64
-	Float32Field                 float32
-	Float64Field                 float64
-	SliceField                   []string
-	MapField                     map[string]string
-	ChanField                    chan any
-	FuncField                    func() string
-	StructField                  struct{ ID string }
-	FromStringSliceToStringField string
-	FromTimeToStringField        string
-	FromTimeToTimeField          time.Time
-	FromStringToTimeField        time.Time
+	StringField           string
+	BoolField             bool
+	IntField              int
+	Int8Field             int8
+	Int16Field            int16
+	Int32Field            int32
+	Int64Field            int64
+	UintField             uint
+	Uint8Field            uint8
+	Uint16Field           uint16
+	Uint32Field           uint32
+	Uint64Field           uint64
+	Float32Field          float32
+	Float64Field          float64
+	MapField              map[string]string
+	ChanField             chan any
+	FuncField             func() string
+	StructField           struct{ ID string }
+	FromTimeToStringField string
+	FromTimeToTimeField   time.Time
+	FromStringToTimeField time.Time
 }
 
 func (to AssignTagTo) checkFields(t *testing.T, from AssignTagFrom) {
@@ -159,13 +153,6 @@ func (to AssignTagTo) checkFields(t *testing.T, from AssignTagFrom) {
 			from.Float64Field, to.Float64Field))
 	}
 
-	for i, value := range from.SliceField {
-		if value != to.SliceField[i] {
-			t.Fatalf("%+v\n", errors.Errorf("SliceField not equal: from %v, to %v",
-				value, to.SliceField[i]))
-		}
-	}
-
 	for key, value := range from.MapField {
 		if value != to.MapField[key] {
 			t.Fatalf("%+v\n", errors.Errorf("MapField not equal: from %v, to %v",
@@ -188,11 +175,6 @@ func (to AssignTagTo) checkFields(t *testing.T, from AssignTagFrom) {
 			from.StructField.ID, to.StructField.ID))
 	}
 
-	if strings.Join(from.FromStringSliceToStringField, "::") != to.FromStringSliceToStringField {
-		t.Fatalf("%+v\n", errors.Errorf("FromStringSliceToStringField not equal: from %v, to %v",
-			strings.Join(from.FromStringSliceToStringField, "::"), to.FromStringSliceToStringField))
-	}
-
 	if from.FromTimeToStringField.Format(time.DateTime) != to.FromTimeToStringField {
 		t.Fatalf("%+v\n", errors.Errorf("FromTimeToStringField not equal: from %v, to %v",
 			from.FromTimeToStringField.Format(time.DateTime), to.FromTimeToStringField))
@@ -209,30 +191,114 @@ func (to AssignTagTo) checkFields(t *testing.T, from AssignTagFrom) {
 	}
 }
 
+func (to AssignTagTo) checkNil(t *testing.T) {
+	if to.StringField != "" {
+		t.Fatalf("%+v\n", errors.New("StringField not zero"))
+	}
+
+	if to.BoolField != false {
+		t.Fatalf("%+v\n", errors.New("BoolField not zero"))
+	}
+
+	if to.IntField != 0 {
+		t.Fatalf("%+v\n", errors.New("IntField not zero"))
+	}
+
+	if to.Int8Field != 0 {
+		t.Fatalf("%+v\n", errors.New("Int8Field not zero"))
+	}
+
+	if to.Int16Field != 0 {
+		t.Fatalf("%+v\n", errors.New("Int16Field not zero"))
+	}
+
+	if to.Int32Field != 0 {
+		t.Fatalf("%+v\n", errors.New("Int32Field not zero"))
+	}
+
+	if to.Int64Field != 0 {
+		t.Fatalf("%+v\n", errors.New("Int64Field not zero"))
+	}
+
+	if to.UintField != 0 {
+		t.Fatalf("%+v\n", errors.New("UintField not zero"))
+	}
+
+	if to.Uint8Field != 0 {
+		t.Fatalf("%+v\n", errors.New("Uint8Field not zero"))
+	}
+
+	if to.Uint16Field != 0 {
+		t.Fatalf("%+v\n", errors.New("Uint16Field not zero"))
+	}
+
+	if to.Uint32Field != 0 {
+		t.Fatalf("%+v\n", errors.New("Uint32Field not zero"))
+	}
+
+	if to.Uint64Field != 0 {
+		t.Fatalf("%+v\n", errors.New("Uint64Field not zero"))
+	}
+
+	if to.Float32Field != 0 {
+		t.Fatalf("%+v\n", errors.New("Float32Field not zero"))
+	}
+
+	if to.Float64Field != 0 {
+		t.Fatalf("%+v\n", errors.New("Float64Field not zero"))
+	}
+
+	if to.MapField != nil {
+		t.Fatalf("%+v\n", errors.New("MapField not zero"))
+	}
+
+	if to.ChanField != nil {
+		t.Fatalf("%+v\n", errors.New("ChanField not zero"))
+	}
+
+	if to.FuncField != nil {
+		t.Fatalf("%+v\n", errors.New("FuncField not zero"))
+	}
+
+	if to.StructField.ID != "" {
+		t.Fatalf("%+v\n", errors.New("StructField not zero"))
+	}
+
+	if to.FromTimeToStringField != "" {
+		t.Fatalf("%+v\n", errors.New("FromTimeToStringField not zero"))
+	}
+
+	if !to.FromTimeToTimeField.IsZero() {
+		t.Fatalf("%+v\n", errors.New("FromTimeToTimeField not zero"))
+	}
+
+	if !to.FromStringToTimeField.IsZero() {
+		t.Fatalf("%+v\n", errors.New("FromStringToTimeField not zero"))
+	}
+}
+
 type AssignTagToPointerField struct {
-	StringField                  *string
-	BoolField                    *bool
-	IntField                     *int
-	Int8Field                    *int8
-	Int16Field                   *int16
-	Int32Field                   *int32
-	Int64Field                   *int64
-	UintField                    *uint
-	Uint8Field                   *uint8
-	Uint16Field                  *uint16
-	Uint32Field                  *uint32
-	Uint64Field                  *uint64
-	Float32Field                 *float32
-	Float64Field                 *float64
-	SliceField                   *[]string
-	MapField                     *map[string]string
-	ChanField                    *chan any
-	FuncField                    *func() string
-	StructField                  *struct{ ID string }
-	FromStringSliceToStringField *string
-	FromTimeToStringField        *string
-	FromTimeToTimeField          *time.Time
-	FromStringToTimeField        *time.Time
+	StringField           *string
+	BoolField             *bool
+	IntField              *int
+	Int8Field             *int8
+	Int16Field            *int16
+	Int32Field            *int32
+	Int64Field            *int64
+	UintField             *uint
+	Uint8Field            *uint8
+	Uint16Field           *uint16
+	Uint32Field           *uint32
+	Uint64Field           *uint64
+	Float32Field          *float32
+	Float64Field          *float64
+	MapField              *map[string]string
+	ChanField             *chan any
+	FuncField             *func() string
+	StructField           *struct{ ID string }
+	FromTimeToStringField *string
+	FromTimeToTimeField   *time.Time
+	FromStringToTimeField *time.Time
 }
 
 func (to AssignTagToPointerField) checkFields(t *testing.T, from AssignTagFrom) {
@@ -306,13 +372,6 @@ func (to AssignTagToPointerField) checkFields(t *testing.T, from AssignTagFrom)
 			from.Float64Field, *to.Float64Field))
 	}
 
-	for i, value := range from.SliceField {
-		if value != (*to.SliceField)[i] {
-			t.Fatalf("%+v\n", errors.Errorf("SliceField not equal: from %v, to %v",
-				value, (*to.SliceField)[i]))
-		}
-	}
-
 	for key, value := range from.MapField {
 		if value != (*to.MapField)[key] {
 			t.Fatalf("%+v\n", errors.Errorf("MapField not equal: from %v, to %v",
@@ -335,11 +394,6 @@ func (to AssignTagToPointerField) checkFields(t *testing.T, from AssignTagFrom)
 			from.StructField.ID, (*to.StructField).ID))
 	}
 
-	if strings.Join(from.FromStringSliceToStringField, "::") != *to.FromStringSliceToStringField {
-		t.Fatalf("%+v\n", errors.Errorf("FromStringSliceToStringField not equal: from %v, to %v",
-			strings.Join(from.FromStringSliceToStringField, "::"), to.FromStringSliceToStringField))
-	}
-
 	if from.FromTimeToStringField.Format(time.DateTime) != *to.FromTimeToStringField {
 		t.Fatalf("%+v\n", errors.Errorf("FromTimeToStringField not equal: from %v, to %v",
 			from.FromTimeToStringField.Format(time.DateTime), to.FromTimeToStringField))
@@ -356,6 +410,92 @@ func (to AssignTagToPointerField) checkFields(t *testing.T, from AssignTagFrom)
 	}
 }
 
+func (to AssignTagToPointerField) checkNil(t *testing.T) {
+	if to.StringField != nil {
+		t.Fatalf("%+v\n", errors.New("StringField not nil"))
+	}
+
+	if to.BoolField != nil {
+		t.Fatalf("%+v\n", errors.New("BoolField not nil"))
+	}
+
+	if to.IntField != nil {
+		t.Fatalf("%+v\n", errors.New("IntField not nil"))
+	}
+
+	if to.Int8Field != nil {
+		t.Fatalf("%+v\n", errors.New("Int8Field not nil"))
+	}
+
+	if to.Int16Field != nil {
+		t.Fatalf("%+v\n", errors.New("Int16Field not nil"))
+	}
+
+	if to.Int32Field != nil {
+		t.Fatalf("%+v\n", errors.New("Int32Field not nil"))
+	}
+
+	if to.Int64Field != nil {
+		t.Fatalf("%+v\n", errors.New("Int64Field not nil"))
+	}
+
+	if to.UintField != nil {
+		t.Fatalf("%+v\n", errors.New("UintField not nil"))
+	}
+
+	if to.Uint8Field != nil {
+		t.Fatalf("%+v\n", errors.New("Uint8Field not nil"))
+	}
+
+	if to.Uint16Field != nil {
+		t.Fatalf("%+v\n", errors.New("Uint16Field not nil"))
+	}
+
+	if to.Uint32Field != nil {
+		t.Fatalf("%+v\n", errors.New("Uint32Field not nil"))
+	}
+
+	if to.Uint64Field != nil {
+		t.Fatalf("%+v\n", errors.New("Uint64Field not nil"))
+	}
+
+	if to.Float32Field != nil {
+		t.Fatalf("%+v\n", errors.New("Float32Field not nil"))
+	}
+
+	if to.Float64Field != nil {
+		t.Fatalf("%+v\n", errors.New("Float64Field not nil"))
+	}
+
+	if to.MapField != nil {
+		t.Fatalf("%+v\n", errors.New("MapField not nil"))
+	}
+
+	if to.ChanField != nil {
+		t.Fatalf("%+v\n", errors.New("ChanField not nil"))
+	}
+
+	if to.FuncField != nil {
+		t.Fatalf("%+v\n", errors.New("ChanField not nil"))
+	}
+
+	if to.StructField != nil {
+		t.Fatalf("%+v\n", errors.New("ChanField not nil"))
+	}
+
+	if to.FromTimeToStringField != nil {
+		t.Fatalf("%+v\n", errors.New("ChanField not nil"))
+	}
+
+	if to.FromTimeToTimeField != nil {
+		t.Fatalf("%+v\n", errors.New("ChanField not nil"))
+	}
+
+	if to.FromStringToTimeField != nil {
+		t.Fatalf("%+v\n", errors.New("ChanField not nil"))
+	}
+}
+
 func TestAssignTagDefaultUsage(t *testing.T) {
 	stringField := strutils.SimpleUUID()
 	boolField := rand.Intn(2) == 0
@@ -371,67 +511,61 @@ func TestAssignTagDefaultUsage(t *testing.T) {
 	uint64Field := uint64(rand.Int())
 	float32Field := rand.Float32()
 	float64Field := rand.Float64()
-	sliceField := []string{strutils.SimpleUUID(), strutils.SimpleUUID()}
 	mapField := map[string]string{strutils.SimpleUUID(): strutils.SimpleUUID()}
 	chanField := make(chan any)
 	returnValue := strutils.SimpleUUID()
 	funcField := func() string { return returnValue }
 	structField := struct{ ID string }{ID: strutils.SimpleUUID()}
-	fromStringSliceToStringField := []string{strutils.SimpleUUID(), strutils.SimpleUUID()}
 	fromTimeToStringField := time.Now().Local()
 	fromTimeToTimeField := time.Now().Local()
 	fromStringToTimeField := time.Now().Local().Format(time.DateTime)
 
 	from := AssignTagFrom{
-		StringField:                  stringField,
-		BoolField:                    boolField,
-		IntField:                     intField,
-		Int8Field:                    int8Field,
-		Int16Field:                   int16Field,
-		Int32Field:                   int32Field,
-		Int64Field:                   int64Field,
-		UintField:                    uintField,
-		Uint8Field:                   uint8Field,
-		Uint16Field:                  uint16Field,
-		Uint32Field:                  uint32Field,
-		Uint64Field:                  uint64Field,
-		Float32Field:                 float32Field,
-		Float64Field:                 float64Field,
-		SliceField:                   sliceField,
-		MapField:                     mapField,
-		ChanField:                    chanField,
-		FuncField:                    funcField,
-		StructField:                  structField,
-		FromStringSliceToStringField: fromStringSliceToStringField,
-		FromTimeToStringField:        fromTimeToStringField,
-		FromTimeToTimeField:          fromTimeToTimeField,
-		FromStringToTimeField:        fromStringToTimeField,
+		StringField:           stringField,
+		BoolField:             boolField,
+		IntField:              intField,
+		Int8Field:             int8Field,
+		Int16Field:            int16Field,
+		Int32Field:            int32Field,
+		Int64Field:            int64Field,
+		UintField:             uintField,
+		Uint8Field:            uint8Field,
+		Uint16Field:           uint16Field,
+		Uint32Field:           uint32Field,
+		Uint64Field:           uint64Field,
+		Float32Field:          float32Field,
+		Float64Field:          float64Field,
+		MapField:              mapField,
+		ChanField:             chanField,
+		FuncField:             funcField,
+		StructField:           structField,
+		FromTimeToStringField: fromTimeToStringField,
+		FromTimeToTimeField:   fromTimeToTimeField,
+		FromStringToTimeField: fromStringToTimeField,
 	}
 
 	fromPointer := AssignTagFromPointerField{
-		StringField:                  &stringField,
-		BoolField:                    &boolField,
-		IntField:                     &intField,
-		Int8Field:                    &int8Field,
-		Int16Field:                   &int16Field,
-		Int32Field:                   &int32Field,
-		Int64Field:                   &int64Field,
-		UintField:                    &uintField,
-		Uint8Field:                   &uint8Field,
-		Uint16Field:                  &uint16Field,
-		Uint32Field:                  &uint32Field,
-		Uint64Field:                  &uint64Field,
-		Float32Field:                 &float32Field,
-		Float64Field:                 &float64Field,
-		SliceField:                   &sliceField,
-		MapField:                     &mapField,
-		ChanField:                    &chanField,
-		FuncField:                    &funcField,
-		StructField:                  &structField,
-		FromStringSliceToStringField: &fromStringSliceToStringField,
-		FromTimeToStringField:        &fromTimeToStringField,
-		FromTimeToTimeField:          &fromTimeToTimeField,
-		FromStringToTimeField:        &fromStringToTimeField,
+		StringField:           &stringField,
+		BoolField:             &boolField,
+		IntField:              &intField,
+		Int8Field:             &int8Field,
+		Int16Field:            &int16Field,
+		Int32Field:            &int32Field,
+		Int64Field:            &int64Field,
+		UintField:             &uintField,
+		Uint8Field:            &uint8Field,
+		Uint16Field:           &uint16Field,
+		Uint32Field:           &uint32Field,
+		Uint64Field:           &uint64Field,
+		Float32Field:          &float32Field,
+		Float64Field:          &float64Field,
+		MapField:              &mapField,
+		ChanField:             &chanField,
+		FuncField:             &funcField,
+		StructField:           &structField,
+		FromTimeToStringField: &fromTimeToStringField,
+		FromTimeToTimeField:   &fromTimeToTimeField,
+		FromStringToTimeField: &fromStringToTimeField,
 	}
 
 	fromPointerNil := AssignTagFromPointerField{}
@@ -466,6 +600,9 @@ func TestAssignTagDefaultUsage(t *testing.T) {
 
 	to.checkFields(t, from)
 
+	to = AssignTagTo{}
+	toPointer = AssignTagToPointerField{}
+
 	err = assign.DefaultUsage(from, &toPointer)
 	if err != nil {
 		t.Fatalf("%+v\n", err)
@@ -473,6 +610,9 @@ func TestAssignTagDefaultUsage(t *testing.T) {
 
 	toPointer.checkFields(t, from)
 
+	to = AssignTagTo{}
+	toPointer = AssignTagToPointerField{}
+
 	err = assign.DefaultUsage(fromPointer, &to)
 	if err != nil {
 		t.Fatalf("%+v\n", err)
@@ -480,6 +620,9 @@ func TestAssignTagDefaultUsage(t *testing.T) {
 
 	to.checkFields(t, from)
 
+	to = AssignTagTo{}
+	toPointer = AssignTagToPointerField{}
+
 	err = assign.DefaultUsage(fromPointer, &toPointer)
 	if err != nil {
 		t.Fatalf("%+v\n", err)
@@ -487,6 +630,9 @@ func TestAssignTagDefaultUsage(t *testing.T) {
 
 	toPointer.checkFields(t, from)
 
+	to = AssignTagTo{}
+	toPointer = AssignTagToPointerField{}
+
 	err = assign.DefaultUsage(&from, to)
 	if err == nil || err.Error() != "返回类型不是结构指针" {
 		t.Fatalf("%+v\n", errors.Errorf("没有检测出to参数必须是指针类型"))
@@ -514,6 +660,9 @@ func TestAssignTagDefaultUsage(t *testing.T) {
 
 	to.checkFields(t, from)
 
+	to = AssignTagTo{}
+	toPointer = AssignTagToPointerField{}
+
 	err = assign.DefaultUsage(&from, &toPointer)
 	if err != nil {
 		t.Fatalf("%+v\n", err)
@@ -521,6 +670,9 @@ func TestAssignTagDefaultUsage(t *testing.T) {
 
 	toPointer.checkFields(t, from)
 
+	to = AssignTagTo{}
+	toPointer = AssignTagToPointerField{}
+
 	err = assign.DefaultUsage(&fromPointer, &to)
 	if err != nil {
 		t.Fatalf("%+v\n", err)
@@ -528,6 +680,9 @@ func TestAssignTagDefaultUsage(t *testing.T) {
 
 	to.checkFields(t, from)
 
+	to = AssignTagTo{}
+	toPointer = AssignTagToPointerField{}
+
 	err = assign.DefaultUsage(&fromPointer, &toPointer)
 	if err != nil {
 		t.Fatalf("%+v\n", err)
@@ -535,27 +690,835 @@ func TestAssignTagDefaultUsage(t *testing.T) {
 
 	toPointer.checkFields(t, from)
 
+	to = AssignTagTo{}
+	toPointer = AssignTagToPointerField{}
+
 	err = assign.DefaultUsage(fromPointerNil, &to)
-	if err == nil || err.Error() != "无法设置值,请检查是否传递的是非指针结构变量且字段为nil" {
-		t.Fatalf("%+v\n", errors.Errorf("没有检测出from如果有nil字段,必须使用指针结构变量"))
+	if err != nil {
+		t.Fatalf("%+v\n", err)
 	}
 
+	to.checkNil(t)
+
+	to = AssignTagTo{}
+	toPointer = AssignTagToPointerField{}
+
 	err = assign.DefaultUsage(fromPointerNil, &toPointer)
-	if err == nil || err.Error() != "无法设置值,请检查是否传递的是非指针结构变量且字段为nil" {
-		t.Fatalf("%+v\n", errors.Errorf("没有检测出from如果有nil字段,必须使用指针结构变量"))
+	if err != nil {
+		t.Fatalf("%+v\n", err)
 	}
 
+	toPointer.checkNil(t)
+
+	to = AssignTagTo{}
+	toPointer = AssignTagToPointerField{}
+
 	err = assign.DefaultUsage(&fromPointerNil, &to)
 	if err != nil {
 		t.Fatalf("%+v\n", err)
 	}
 
-	to.checkFields(t, from)
+	to.checkNil(t)
+
+	to = AssignTagTo{}
+	toPointer = AssignTagToPointerField{}
 
 	err = assign.DefaultUsage(&fromPointerNil, &toPointer)
 	if err != nil {
 		t.Fatalf("%+v\n", err)
 	}
 
+	toPointer.checkNil(t)
+}
+
+type AssignTagFromSlice struct {
+	BasicField                          string               `assign:"toField:BasicField"`
+	BasicSliceField                     []string             `assign:"toField:BasicSliceField"`
+	TimeSliceField                      []time.Time          `assign:"toField:TimeSliceField"`
+	StructSliceField                    []AssignTagFrom      `assign:"toField:StructSliceField"`
+	MapSliceField                       []map[string]string  `assign:"toField:MapSliceField"`
+	ChanSliceField                      []chan any           `assign:"toField:ChanSliceField"`
+	FuncSliceField                      []func() string      `assign:"toField:FuncSliceField"`
+	FromStringSliceToStringField        []string             `assign:"toField:FromStringSliceToStringField"`
+	FromTimeToStringField               []time.Time          `assign:"toField:FromTimeToStringField"`
+	FromStringToTimeField               []string             `assign:"toField:FromStringToTimeField"`
+	BasicPointerSliceField              []*string            `assign:"toField:BasicPointerSliceField"`
+	TimePointerSliceField               []*time.Time         `assign:"toField:TimePointerSliceField"`
+	StructPointerSliceField             []*AssignTagFrom     `assign:"toField:StructPointerSliceField"`
+	MapPointerSliceField                []*map[string]string `assign:"toField:MapPointerSliceField"`
+	ChanPointerSliceField               []*chan any          `assign:"toField:ChanPointerSliceField"`
+	FuncPointerSliceField               []*func() string     `assign:"toField:FuncPointerSliceField"`
+	FromStringSliceToStringPointerField []*string            `assign:"toField:FromStringSliceToStringPointerField"`
+	FromTimeToStringPointerField        []*time.Time         `assign:"toField:FromTimeToStringPointerField"`
+	FromStringToTimePointerField        []*string            `assign:"toField:FromStringToTimePointerField"`
+}
+
+type AssignTagFromSlicePointerField struct {
+	BasicField                          *string               `assign:"toField:BasicField"`
+	BasicSliceField                     *[]string             `assign:"toField:BasicSliceField"`
+	TimeSliceField                      *[]time.Time          `assign:"toField:TimeSliceField"`
+	StructSliceField                    *[]AssignTagFrom      `assign:"toField:StructSliceField"`
+	MapSliceField                       *[]map[string]string  `assign:"toField:MapSliceField"`
+	ChanSliceField                      *[]chan any           `assign:"toField:ChanSliceField"`
+	FuncSliceField                      *[]func() string      `assign:"toField:FuncSliceField"`
+	FromStringSliceToStringField        *[]string             `assign:"toField:FromStringSliceToStringField"`
+	FromTimeToStringField               *[]time.Time          `assign:"toField:FromTimeToStringField"`
+	FromStringToTimeField               *[]string             `assign:"toField:FromStringToTimeField"`
+	BasicPointerSliceField              *[]*string            `assign:"toField:BasicPointerSliceField"`
+	TimePointerSliceField               *[]*time.Time         `assign:"toField:TimePointerSliceField"`
+	StructPointerSliceField             *[]*AssignTagFrom     `assign:"toField:StructPointerSliceField"`
+	MapPointerSliceField                *[]*map[string]string `assign:"toField:MapPointerSliceField"`
+	ChanPointerSliceField               *[]*chan any          `assign:"toField:ChanPointerSliceField"`
+	FuncPointerSliceField               *[]*func() string     `assign:"toField:FuncPointerSliceField"`
+	FromStringSliceToStringPointerField *[]*string            `assign:"toField:FromStringSliceToStringPointerField"`
+	FromTimeToStringPointerField        *[]*time.Time         `assign:"toField:FromTimeToStringPointerField"`
+	FromStringToTimePointerField        *[]*string            `assign:"toField:FromStringToTimePointerField"`
+}
+
+type AssignTagToSlice struct {
+	BasicField                          string
+	BasicSliceField                     []string
+	TimeSliceField                      []time.Time
+	StructSliceField                    []AssignTagTo
+	MapSliceField                       []map[string]string
+	ChanSliceField                      []chan any
+	FuncSliceField                      []func() string
+	FromStringSliceToStringField        string
+	FromTimeToStringField               []string
+	FromStringToTimeField               []time.Time
+	BasicPointerSliceField              []*string
+	TimePointerSliceField               []*time.Time
+	StructPointerSliceField             []*AssignTagTo
+	MapPointerSliceField                []*map[string]string
+	ChanPointerSliceField               []*chan any
+	FuncPointerSliceField               []*func() string
+	FromStringSliceToStringPointerField string
+	FromTimeToStringPointerField        []*string
+	FromStringToTimePointerField        []*time.Time
+}
+
+func (to AssignTagToSlice) checkFields(t *testing.T, from AssignTagFromSlice) {
+	if from.BasicField != to.BasicField {
+		t.Fatalf("%+v\n", errors.Errorf("BasicField not equal: from %v, to %v",
+			from.BasicField, to.BasicField))
+	}
+
+	for i, value := range from.BasicSliceField {
+		if value != to.BasicSliceField[i] {
+			t.Fatalf("%+v\n", errors.Errorf("BasicSliceField not equal: from %v, to %v",
+				value, to.BasicSliceField[i]))
+		}
+	}
+
+	for i, value := range from.TimeSliceField {
+		if !value.Equal(to.TimeSliceField[i]) {
+			t.Fatalf("%+v\n", errors.Errorf("TimeSliceField not equal: from %v, to %v",
+				value, to.TimeSliceField[i]))
+		}
+	}
+
+	for i, value := range from.StructSliceField {
+		to.StructSliceField[i].checkFields(t, value)
+	}
+
+	for i, value := range from.MapSliceField {
+		for k, v := range value {
+			if v != to.MapSliceField[i][k] {
+				t.Fatalf("%+v\n", errors.Errorf("MapSliceField not equal: from %v, to %v",
+					value, to.MapSliceField[i][k]))
+			}
+		}
+	}
+
+	for i, value := range from.ChanSliceField {
+		if value != to.ChanSliceField[i] {
+			t.Fatalf("%+v\n", errors.Errorf("ChanSliceField not equal: from %v, to %v",
+				value, to.ChanSliceField[i]))
+		}
+	}
+
+	for i, value := range from.FuncSliceField {
+		if value() != to.FuncSliceField[i]() {
+			t.Fatalf("%+v\n", errors.Errorf("FuncSliceField not equal: from %v, to %v",
+				value(), to.FuncSliceField[i]()))
+		}
+	}
+
+	if strings.Join(from.FromStringSliceToStringField, "::") != to.FromStringSliceToStringField {
+		t.Fatalf("%+v\n", errors.Errorf("FromStringSliceToStringField not equal: from %v, to %v",
+			strings.Join(from.FromStringSliceToStringField, "::"), to.FromStringSliceToStringField))
+	}
+
+	for i, value := range from.FromTimeToStringField {
+		if value.Format(time.DateTime) != to.FromTimeToStringField[i] {
+			t.Fatalf("%+v\n", errors.Errorf("FromTimeToStringField not equal: from %v, to %v",
+				value.Format(time.DateTime), to.FromTimeToStringField[i]))
+		}
+	}
+
+	for i, value := range from.FromStringToTimeField {
+		if value != to.FromStringToTimeField[i].Format(time.DateTime) {
+			t.Fatalf("%+v\n", errors.Errorf("FromStringToTimeField not equal: from %v, to %v",
+				value, to.FromStringToTimeField[i].Format(time.DateTime)))
+		}
+	}
+
+	for i, value := range from.BasicPointerSliceField {
+		if *value != *to.BasicPointerSliceField[i] {
+			t.Fatalf("%+v\n", errors.Errorf("BasicPointerSliceField not equal: from %v, to %v",
+				value, to.BasicPointerSliceField[i]))
+		}
+	}
+
+	for i, value := range from.TimePointerSliceField {
+		if !value.Equal(*to.TimePointerSliceField[i]) {
+			t.Fatalf("%+v\n", errors.Errorf("TimeSliceField not equal: from %v, to %v",
+				value, *to.TimePointerSliceField[i]))
+		}
+	}
+
+	for i, value := range from.StructPointerSliceField {
+		to.StructSliceField[i].checkFields(t, *value)
+	}
+
+	for i, value := range from.MapPointerSliceField {
+		for k, v := range *value {
+			if v != (*to.MapPointerSliceField[i])[k] {
+				t.Fatalf("%+v\n", errors.Errorf("MapPointerSliceField not equal: from %v, to %v",
+					value, (*to.MapPointerSliceField[i])[k]))
+			}
+		}
+	}
+
+	for i, value := range from.ChanPointerSliceField {
+		if value != to.ChanPointerSliceField[i] {
+			t.Fatalf("%+v\n", errors.Errorf("ChanPointerSliceField not equal: from %v, to %v",
+				value, to.ChanPointerSliceField[i]))
+		}
+	}
+
+	for i, value := range from.FuncPointerSliceField {
+		if (*value)() != (*to.FuncPointerSliceField[i])() {
+			t.Fatalf("%+v\n", errors.Errorf("FuncPointerSliceField not equal: from %v, to %v",
+				(*value)(), (*to.FuncPointerSliceField[i])()))
+		}
+	}
+
+	toStringSliceToStringSlice := strings.Split(to.FromStringSliceToStringPointerField, "::")
+	for i, value := range from.FromStringSliceToStringPointerField {
+		if *value != toStringSliceToStringSlice[i] {
+			t.Fatalf("%+v\n", errors.Errorf("FromStringSliceToStringPointerField not equal: from %v, to %v",
+				*value, toStringSliceToStringSlice[i]))
+		}
+	}
+
+	for i, value := range from.FromTimeToStringPointerField {
+		if value.Format(time.DateTime) != *to.FromTimeToStringPointerField[i] {
+			t.Fatalf("%+v\n", errors.Errorf("FromTimeToStringPointerField not equal: from %v, to %v",
+				value.Format(time.DateTime), *to.FromTimeToStringPointerField[i]))
+		}
+	}
+
+	for i, value := range from.FromStringToTimePointerField {
+		if *value != (*to.FromStringToTimePointerField[i]).Format(time.DateTime) {
+			t.Fatalf("%+v\n", errors.Errorf("FromStringToTimePointerField not equal: from %v, to %v",
+				*value, (*to.FromStringToTimePointerField[i]).Format(time.DateTime)))
+		}
+	}
+}
+
+func (to AssignTagToSlice) checkNil(t *testing.T) {
+	if to.BasicField != "" {
+		t.Fatalf("%+v\n", errors.Errorf("BasicField not zero"))
+	}
+
+	if to.BasicSliceField != nil {
+		t.Fatalf("%+v\n", errors.Errorf("BasicSliceField not nil"))
+	}
+
+	if to.TimeSliceField != nil {
+		t.Fatalf("%+v\n", errors.Errorf("TimeSliceField not nil"))
+	}
+
+	if to.StructSliceField != nil {
+		t.Fatalf("%+v\n", errors.Errorf("StructSliceField not nil"))
+	}
+
+	if to.MapSliceField != nil {
+		t.Fatalf("%+v\n", errors.Errorf("MapSliceField not nil"))
+	}
+
+	if to.ChanSliceField != nil {
+		t.Fatalf("%+v\n", errors.Errorf("ChanSliceField not nil"))
+	}
+
+	if to.FuncSliceField != nil {
+		t.Fatalf("%+v\n", errors.Errorf("FuncSliceField not nil"))
+	}
+
+	if to.FromStringSliceToStringField != "" {
+		t.Fatalf("%+v\n", errors.Errorf("FromStringSliceToStringField not zero"))
+	}
+
+	if to.FromTimeToStringField != nil {
+		t.Fatalf("%+v\n", errors.Errorf("FromTimeToStringField not nil"))
+	}
+
+	if to.FromStringToTimeField != nil {
+		t.Fatalf("%+v\n", errors.Errorf("FromStringToTimeField not nil"))
+	}
+
+	if to.BasicPointerSliceField != nil {
+		t.Fatalf("%+v\n", errors.Errorf("BasicPointerSliceField not nil"))
+	}
+
+	if to.TimePointerSliceField != nil {
+		t.Fatalf("%+v\n", errors.Errorf("TimePointerSliceField not nil"))
+	}
+
+	if to.StructPointerSliceField != nil {
+		t.Fatalf("%+v\n", errors.Errorf("StructPointerSliceField not nil"))
+	}
+
+	if to.MapPointerSliceField != nil {
+		t.Fatalf("%+v\n", errors.Errorf("MapPointerSliceField not nil"))
+	}
+
+	if to.ChanPointerSliceField != nil {
+		t.Fatalf("%+v\n", errors.Errorf("ChanPointerSliceField not nil"))
+	}
+
+	if to.FuncPointerSliceField != nil {
+		t.Fatalf("%+v\n", errors.Errorf("FuncPointerSliceField not nil"))
+	}
+
+	if to.FromStringSliceToStringPointerField != "" {
+		t.Fatalf("%+v\n", errors.Errorf("FromStringSliceToStringPointerField not zero"))
+	}
+
+	if to.FromTimeToStringPointerField != nil {
+		t.Fatalf("%+v\n", errors.Errorf("FromTimeToStringPointerField not nil"))
+	}
+
+	if to.FromStringToTimePointerField != nil {
+		t.Fatalf("%+v\n", errors.Errorf("FromStringToTimePointerField not nil"))
+	}
+}
+
+type AssignTagToSlicePointerField struct {
+	BasicField                          *string
+	BasicSliceField                     *[]string
+	TimeSliceField                      *[]time.Time
+	StructSliceField                    *[]AssignTagTo
+	MapSliceField                       *[]map[string]string
+	ChanSliceField                      *[]chan any
+	FuncSliceField                      *[]func() string
+	FromStringSliceToStringField        *string
+	FromTimeToStringField               *[]string
+	FromStringToTimeField               *[]time.Time
+	BasicPointerSliceField              *[]*string
+	TimePointerSliceField               *[]*time.Time
+	StructPointerSliceField             *[]*AssignTagTo
+	MapPointerSliceField                *[]*map[string]string
+	ChanPointerSliceField               *[]*chan any
+	FuncPointerSliceField               *[]*func() string
+	FromStringSliceToStringPointerField *string
+	FromTimeToStringPointerField        *[]*string
+	FromStringToTimePointerField        *[]*time.Time
+}
+
+func (to AssignTagToSlicePointerField) checkFields(t *testing.T, from AssignTagFromSlice) {
+	if from.BasicField != *to.BasicField {
+		t.Fatalf("%+v\n", errors.Errorf("BasicField not equal: from %v, to %v",
+			from.BasicField, *to.BasicField))
+	}
+
+	for i, value := range from.BasicSliceField {
+		if value != (*to.BasicSliceField)[i] {
+			t.Fatalf("%+v\n", errors.Errorf("BasicSliceField not equal: from %v, to %v",
+				value, (*to.BasicSliceField)[i]))
+		}
+	}
+
+	for i, value := range from.TimeSliceField {
+		if !value.Equal((*to.TimeSliceField)[i]) {
+			t.Fatalf("%+v\n", errors.Errorf("TimeSliceField not equal: from %v, to %v",
+				value, (*to.TimeSliceField)[i]))
+		}
+	}
+
+	for i, value := range from.StructSliceField {
+		(*to.StructSliceField)[i].checkFields(t, value)
+	}
+
+	for i, value := range from.MapSliceField {
+		for k, v := range value {
+			if v != (*to.MapSliceField)[i][k] {
+				t.Fatalf("%+v\n", errors.Errorf("MapSliceField not equal: from %v, to %v",
+					value, (*to.MapSliceField)[i][k]))
+			}
+		}
+	}
+
+	for i, value := range from.ChanSliceField {
+		if value != (*to.ChanSliceField)[i] {
+			t.Fatalf("%+v\n", errors.Errorf("ChanSliceField not equal: from %v, to %v",
+				value, (*to.ChanSliceField)[i]))
+		}
+	}
+
+	for i, value := range from.FuncSliceField {
+		if value() != (*to.FuncSliceField)[i]() {
+			t.Fatalf("%+v\n", errors.Errorf("FuncSliceField not equal: from %v, to %v",
+				value(), (*to.FuncSliceField)[i]()))
+		}
+	}
+
+	if strings.Join(from.FromStringSliceToStringField, "::") != *to.FromStringSliceToStringField {
+		t.Fatalf("%+v\n", errors.Errorf("FromStringSliceToStringField not equal: from %v, to %v",
+			strings.Join(from.FromStringSliceToStringField, "::"), *to.FromStringSliceToStringField))
+	}
+
+	for i, value := range from.FromTimeToStringField {
+		if value.Format(time.DateTime) != (*to.FromTimeToStringField)[i] {
+			t.Fatalf("%+v\n", errors.Errorf("FromTimeToStringField not equal: from %v, to %v",
+				value.Format(time.DateTime), (*to.FromTimeToStringField)[i]))
+		}
+	}
+
+	for i, value := range from.FromStringToTimeField {
+		if value != (*to.FromStringToTimeField)[i].Format(time.DateTime) {
+			t.Fatalf("%+v\n", errors.Errorf("FromStringToTimeField not equal: from %v, to %v",
+				value, (*to.FromStringToTimeField)[i].Format(time.DateTime)))
+		}
+	}
+
+	for i, value := range from.BasicPointerSliceField {
+		if *value != *(*to.BasicPointerSliceField)[i] {
+			t.Fatalf("%+v\n", errors.Errorf("BasicPointerSliceField not equal: from %v, to %v",
+				value, *(*to.BasicPointerSliceField)[i]))
+		}
+	}
+
+	for i, value := range from.TimePointerSliceField {
+		if !value.Equal(*(*to.TimePointerSliceField)[i]) {
+			t.Fatalf("%+v\n", errors.Errorf("TimeSliceField not equal: from %v, to %v",
+				value, *(*to.TimePointerSliceField)[i]))
+		}
+	}
+
+	for i, value := range from.StructPointerSliceField {
+		(*to.StructSliceField)[i].checkFields(t, *value)
+	}
+
+	for i, value := range from.MapPointerSliceField {
+		for k, v := range *value {
+			if v != (*(*to.MapPointerSliceField)[i])[k] {
+				t.Fatalf("%+v\n", errors.Errorf("MapPointerSliceField not equal: from %v, to %v",
+					value, (*(*to.MapPointerSliceField)[i])[k]))
+			}
+		}
+	}
+
+	for i, value := range from.ChanPointerSliceField {
+		if value != (*to.ChanPointerSliceField)[i] {
+			t.Fatalf("%+v\n", errors.Errorf("ChanPointerSliceField not equal: from %v, to %v",
+				value, (*to.ChanPointerSliceField)[i]))
+		}
+	}
+
+	for i, value := range from.FuncPointerSliceField {
+		if (*value)() != (*(*to.FuncPointerSliceField)[i])() {
+			t.Fatalf("%+v\n", errors.Errorf("FuncPointerSliceField not equal: from %v, to %v",
+				(*value)(), (*(*to.FuncPointerSliceField)[i])()))
+		}
+	}
+
+	toStringSliceToStringSlice := strings.Split(*to.FromStringSliceToStringPointerField, "::")
+	for i, value := range from.FromStringSliceToStringPointerField {
+		if *value != toStringSliceToStringSlice[i] {
+			t.Fatalf("%+v\n", errors.Errorf("FromStringSliceToStringPointerField not equal: from %v, to %v",
+				*value, toStringSliceToStringSlice[i]))
+		}
+	}
+
+	for i, value := range from.FromTimeToStringPointerField {
+		if value.Format(time.DateTime) != *(*to.FromTimeToStringPointerField)[i] {
+			t.Fatalf("%+v\n", errors.Errorf("FromTimeToStringPointerField not equal: from %v, to %v",
+				value.Format(time.DateTime), *(*to.FromTimeToStringPointerField)[i]))
+		}
+	}
+
+	for i, value := range from.FromStringToTimePointerField {
+		if *value != (*to.FromStringToTimePointerField)[i].Format(time.DateTime) {
+			t.Fatalf("%+v\n", errors.Errorf("FromStringToTimePointerField not equal: from %v, to %v",
+				*value, (*to.FromStringToTimePointerField)[i].Format(time.DateTime)))
+		}
+	}
+}
+
+func (to AssignTagToSlicePointerField) checkNil(t *testing.T) {
+	if to.BasicField != nil {
+		t.Fatalf("%+v\n", errors.Errorf("BasicField not nil"))
+	}
+
+	if to.BasicSliceField != nil {
+		t.Fatalf("%+v\n", errors.Errorf("BasicSliceField not nil"))
+	}
+
+	if to.TimeSliceField != nil {
+		t.Fatalf("%+v\n", errors.Errorf("TimeSliceField not nil"))
+	}
+
+	if to.StructSliceField != nil {
+		t.Fatalf("%+v\n", errors.Errorf("StructSliceField not nil"))
+	}
+
+	if to.MapSliceField != nil {
+		t.Fatalf("%+v\n", errors.Errorf("MapSliceField not nil"))
+	}
+
+	if to.ChanSliceField != nil {
+		t.Fatalf("%+v\n", errors.Errorf("ChanSliceField not nil"))
+	}
+
+	if to.FuncSliceField != nil {
+		t.Fatalf("%+v\n", errors.Errorf("FuncSliceField not nil"))
+	}
+
+	if to.FromStringSliceToStringField != nil {
+		t.Fatalf("%+v\n", errors.Errorf("FromStringSliceToStringField not nil"))
+	}
+
+	if to.FromTimeToStringField != nil {
+		t.Fatalf("%+v\n", errors.Errorf("FromTimeToStringField not nil"))
+	}
+
+	if to.FromStringToTimeField != nil {
+		t.Fatalf("%+v\n", errors.Errorf("FromStringToTimeField not nil"))
+	}
+
+	if to.BasicPointerSliceField != nil {
+		t.Fatalf("%+v\n", errors.Errorf("BasicPointerSliceField not nil"))
+	}
+
+	if to.TimePointerSliceField != nil {
+		t.Fatalf("%+v\n", errors.Errorf("TimePointerSliceField not nil"))
+	}
+
+	if to.StructPointerSliceField != nil {
+		t.Fatalf("%+v\n", errors.Errorf("StructPointerSliceField not nil"))
+	}
+
+	if to.MapPointerSliceField != nil {
+		t.Fatalf("%+v\n", errors.Errorf("MapPointerSliceField not nil"))
+	}
+
+	if to.ChanPointerSliceField != nil {
+		t.Fatalf("%+v\n", errors.Errorf("ChanPointerSliceField not nil"))
+	}
+
+	if to.FuncPointerSliceField != nil {
+		t.Fatalf("%+v\n", errors.Errorf("FuncPointerSliceField not nil"))
+	}
+
+	if to.FromStringSliceToStringPointerField != nil {
+		t.Fatalf("%+v\n", errors.Errorf("FuncPointerSliceField not nil"))
+	}
+
+	if to.FromTimeToStringPointerField != nil {
+		t.Fatalf("%+v\n", errors.Errorf("FromTimeToStringPointerField not nil"))
+	}
+
+	if to.FromStringToTimePointerField != nil {
+		t.Fatalf("%+v\n", errors.Errorf("FromStringToTimePointerField not nil"))
+	}
+}
+
+func TestAssignTagDefaultUsageSlice(t *testing.T) {
+	retValue1 := strutils.SimpleUUID()
+	retValue2 := strutils.SimpleUUID()
+	str1 := strutils.SimpleUUID()
+	str2 := strutils.SimpleUUID()
+	time1 := time.Now()
+	time2 := time.Now().Add(-1 * time.Hour)
+	map1 := map[string]string{"name": strutils.SimpleUUID()}
+	map2 := map[string]string{"name": strutils.SimpleUUID()}
+	chan1 := make(chan any)
+	chan2 := make(chan any)
+	func1 := func() string { return retValue1 }
+	func2 := func() string { return retValue2 }
+
+	struct1 := AssignTagFrom{
+		StringField:           strutils.SimpleUUID(),
+		BoolField:             rand.Intn(2) == 0,
+		IntField:              rand.Int(),
+		Int8Field:             int8(rand.Int()),
+		Int16Field:            int16(rand.Int()),
+		Int32Field:            int32(rand.Int()),
+		Int64Field:            int64(rand.Int()),
+		UintField:             uint(rand.Int()),
+		Uint8Field:            uint8(rand.Int()),
+		Uint16Field:           uint16(rand.Int()),
+		Uint32Field:           uint32(rand.Int()),
+		Uint64Field:           uint64(rand.Int()),
+		Float32Field:          rand.Float32(),
+		Float64Field:          rand.Float64(),
+		MapField:              map[string]string{strutils.SimpleUUID(): strutils.SimpleUUID()},
+		ChanField:             make(chan any),
+		FuncField:             func() string { return retValue1 },
+		StructField:           struct{ ID string }{ID: strutils.SimpleUUID()},
+		FromTimeToStringField: time.Now().Local(),
+		FromTimeToTimeField:   time.Now().Local(),
+		FromStringToTimeField: time.Now().Local().Format(time.DateTime),
+	}
+	struct2 := AssignTagFrom{
+		StringField:           strutils.SimpleUUID(),
+		BoolField:             rand.Intn(2) == 0,
+		IntField:              rand.Int(),
+		Int8Field:             int8(rand.Int()),
+		Int16Field:            int16(rand.Int()),
+		Int32Field:            int32(rand.Int()),
+		Int64Field:            int64(rand.Int()),
+		UintField:             uint(rand.Int()),
+		Uint8Field:            uint8(rand.Int()),
+		Uint16Field:           uint16(rand.Int()),
+		Uint32Field:           uint32(rand.Int()),
+		Uint64Field:           uint64(rand.Int()),
+		Float32Field:          rand.Float32(),
+		Float64Field:          rand.Float64(),
+		MapField:              map[string]string{strutils.SimpleUUID(): strutils.SimpleUUID()},
+		ChanField:             make(chan any),
+		FuncField:             func() string { return retValue1 },
+		StructField:           struct{ ID string }{ID: strutils.SimpleUUID()},
+		FromTimeToStringField: time.Now().Local(),
+		FromTimeToTimeField:   time.Now().Local(),
+		FromStringToTimeField: time.Now().Local().Format(time.DateTime),
+	}
+
+	basicField := str1
+	basicSliceField := []string{str1, str2}
+	timeSliceField := []time.Time{time1, time2}
+	structSliceField := []AssignTagFrom{struct1, struct2}
+	mapSliceField := []map[string]string{map1, map2}
+	chanSliceField := []chan any{chan1, chan2}
+	funcSliceField := []func() string{func1, func2}
+	basicPointerSliceField := []*string{&str1, &str2}
+	timePointerSliceField := []*time.Time{&time1, &time2}
+	structPointerSliceField := []*AssignTagFrom{&struct1, &struct2}
+	mapPointerSliceField := []*map[string]string{&map1, &map2}
+	chanPointerSliceField := []*chan any{&chan1, &chan2}
+	funcPointerSliceField := []*func() string{&func1, &func2}
+	fromStringSliceToStringField := []string{str1, str2}
+	fromTimeToStringField := []time.Time{time1, time2}
+	fromStringToTimeField := []string{time1.Format(time.DateTime), time2.Format(time.DateTime)}
+	fromStringSliceToStringPointerField := []*string{&str1, &str2}
+	fromTimeToStringPointerField := []*time.Time{&time1, &time2}
+
+	from := AssignTagFromSlice{
+		BasicField:                          basicField,
+		BasicSliceField:                     basicSliceField,
+		TimeSliceField:                      timeSliceField,
+		StructSliceField:                    structSliceField,
+		MapSliceField:                       mapSliceField,
+		ChanSliceField:                      chanSliceField,
+		FuncSliceField:                      funcSliceField,
+		FromStringSliceToStringField:        fromStringSliceToStringField,
+		FromTimeToStringField:               fromTimeToStringField,
+		FromStringToTimeField:               fromStringToTimeField,
+		BasicPointerSliceField:              basicPointerSliceField,
+		TimePointerSliceField:               timePointerSliceField,
+		StructPointerSliceField:             structPointerSliceField,
+		MapPointerSliceField:                mapPointerSliceField,
+		ChanPointerSliceField:               chanPointerSliceField,
+		FuncPointerSliceField:               funcPointerSliceField,
+		FromStringSliceToStringPointerField: fromStringSliceToStringPointerField,
+		FromTimeToStringPointerField:        fromTimeToStringPointerField,
+	}
+
+	fromPointer := AssignTagFromSlicePointerField{
+		BasicField:                          &basicField,
+		BasicSliceField:                     &basicSliceField,
+		TimeSliceField:                      &timeSliceField,
+		StructSliceField:                    &structSliceField,
+		MapSliceField:                       &mapSliceField,
+		ChanSliceField:                      &chanSliceField,
+		FuncSliceField:                      &funcSliceField,
+		FromStringSliceToStringField:        &fromStringSliceToStringField,
+		FromTimeToStringField:               &fromTimeToStringField,
+		FromStringToTimeField:               &fromStringToTimeField,
+		BasicPointerSliceField:              &basicPointerSliceField,
+		TimePointerSliceField:               &timePointerSliceField,
+		StructPointerSliceField:             &structPointerSliceField,
+		MapPointerSliceField:                &mapPointerSliceField,
+		ChanPointerSliceField:               &chanPointerSliceField,
+		FuncPointerSliceField:               &funcPointerSliceField,
+		FromStringSliceToStringPointerField: &fromStringSliceToStringPointerField,
+		FromTimeToStringPointerField:        &fromTimeToStringPointerField,
+	}
+
+	fromPointerNil := AssignTagFromPointerField{}
+
+	to := AssignTagToSlice{}
+	toPointer := AssignTagToSlicePointerField{}
+
+	err := assign.DefaultUsage(from, to)
+	if err == nil || err.Error() != "返回类型不是结构指针" {
+		t.Fatalf("%+v\n", errors.Errorf("没有检测出to参数必须是指针类型"))
+	}
+
+	err = assign.DefaultUsage(from, toPointer)
+	if err == nil || err.Error() != "返回类型不是结构指针" {
+		t.Fatalf("%+v\n", errors.Errorf("没有检测出to参数必须是指针类型"))
+	}
+
+	err = assign.DefaultUsage(fromPointer, to)
+	if err == nil || err.Error() != "返回类型不是结构指针" {
+		t.Fatalf("%+v\n", errors.Errorf("没有检测出to参数必须是指针类型"))
+	}
+
+	err = assign.DefaultUsage(fromPointer, toPointer)
+	if err == nil || err.Error() != "返回类型不是结构指针" {
+		t.Fatalf("%+v\n", errors.Errorf("没有检测出to参数必须是指针类型"))
+	}
+
+	err = assign.DefaultUsage(from, &to)
+	if err != nil {
+		t.Fatalf("%+v\n", err)
+	}
+
+	to.checkFields(t, from)
+
+	to = AssignTagToSlice{}
+	toPointer = AssignTagToSlicePointerField{}
+
+	err = assign.DefaultUsage(from, &toPointer)
+	if err != nil {
+		t.Fatalf("%+v\n", err)
+	}
+
+	toPointer.checkFields(t, from)
+
+	to = AssignTagToSlice{}
+	toPointer = AssignTagToSlicePointerField{}
+
+	err = assign.DefaultUsage(fromPointer, &to)
+	if err != nil {
+		t.Fatalf("%+v\n", err)
+	}
+
+	to.checkFields(t, from)
+
+	to = AssignTagToSlice{}
+	toPointer = AssignTagToSlicePointerField{}
+
+	err = assign.DefaultUsage(fromPointer, &toPointer)
+	if err != nil {
+		t.Fatalf("%+v\n", err)
+	}
+
+	toPointer.checkFields(t, from)
+
+	to = AssignTagToSlice{}
+	toPointer = AssignTagToSlicePointerField{}
+
+	err = assign.DefaultUsage(&from, to)
+	if err == nil || err.Error() != "返回类型不是结构指针" {
+		t.Fatalf("%+v\n", errors.Errorf("没有检测出to参数必须是指针类型"))
+	}
+
+	err = assign.DefaultUsage(&from, toPointer)
+	if err == nil || err.Error() != "返回类型不是结构指针" {
+		t.Fatalf("%+v\n", errors.Errorf("没有检测出to参数必须是指针类型"))
+	}
+
+	err = assign.DefaultUsage(&fromPointer, to)
+	if err == nil || err.Error() != "返回类型不是结构指针" {
+		t.Fatalf("%+v\n", errors.Errorf("没有检测出to参数必须是指针类型"))
+	}
+
+	err = assign.DefaultUsage(&fromPointer, toPointer)
+	if err == nil || err.Error() != "返回类型不是结构指针" {
+		t.Fatalf("%+v\n", errors.Errorf("没有检测出to参数必须是指针类型"))
+	}
+
+	to = AssignTagToSlice{}
+	toPointer = AssignTagToSlicePointerField{}
+
+	err = assign.DefaultUsage(&from, &to)
+	if err != nil {
+		t.Fatalf("%+v\n", err)
+	}
+
+	to.checkFields(t, from)
+
+	to = AssignTagToSlice{}
+	toPointer = AssignTagToSlicePointerField{}
+
+	err = assign.DefaultUsage(&from, &toPointer)
+	if err != nil {
+		t.Fatalf("%+v\n", err)
+	}
+
+	toPointer.checkFields(t, from)
+
+	to = AssignTagToSlice{}
+	toPointer = AssignTagToSlicePointerField{}
+
+	err = assign.DefaultUsage(&fromPointer, &to)
+	if err != nil {
+		t.Fatalf("%+v\n", err)
+	}
+
+	to.checkFields(t, from)
+
+	to = AssignTagToSlice{}
+	toPointer = AssignTagToSlicePointerField{}
+
+	err = assign.DefaultUsage(&fromPointer, &toPointer)
+	if err != nil {
+		t.Fatalf("%+v\n", err)
+	}
+
 	toPointer.checkFields(t, from)
+
+	to = AssignTagToSlice{}
+	toPointer = AssignTagToSlicePointerField{}
+
+	err = assign.DefaultUsage(fromPointerNil, &to)
+	if err != nil {
+		t.Fatalf("%+v\n", err)
+	}
+
+	to.checkNil(t)
+
+	to = AssignTagToSlice{}
+	toPointer = AssignTagToSlicePointerField{}
+
+	err = assign.DefaultUsage(fromPointerNil, &toPointer)
+	if err != nil {
+		t.Fatalf("%+v\n", err)
+	}
+
+	toPointer.checkNil(t)
+
+	to = AssignTagToSlice{}
+	toPointer = AssignTagToSlicePointerField{}
+
+	err = assign.DefaultUsage(&fromPointerNil, &to)
+	if err != nil {
+		t.Fatalf("%+v\n", err)
+	}
+
+	to.checkNil(t)
+
+	to = AssignTagToSlice{}
+	toPointer = AssignTagToSlicePointerField{}
+
+	err = assign.DefaultUsage(&fromPointerNil, &toPointer)
+	if err != nil {
+		t.Fatalf("%+v\n", err)
+	}
+
+	toPointer.checkNil(t)
 }