| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318 |
- package tag
- import (
- "git.sxidc.com/go-tools/utils/reflectutils"
- "git.sxidc.com/go-tools/utils/strutils"
- "git.sxidc.com/service-supports/fserr"
- "git.sxidc.com/service-supports/fslog"
- "reflect"
- "strings"
- "time"
- )
- func AssignTo[T any](from any) (T, error) {
- var zero T
- if from == nil {
- return zero, nil
- }
- fromValue := reflect.ValueOf(from)
- retType := reflect.TypeOf(zero)
- retValue := reflect.New(retType).Elem()
- if retValue.Kind() == reflect.Ptr {
- retValue.Set(reflect.New(retType.Elem()))
- }
- // 类型校验
- if fromValue.Kind() != reflect.Ptr && fromValue.Kind() != reflect.Struct {
- return zero, fserr.New("参数不是结构或结构指针")
- }
- if fromValue.Kind() == reflect.Ptr && fromValue.Elem().Kind() != reflect.Struct {
- return zero, fserr.New("参数不是结构或结构指针")
- }
- if retValue.Kind() != reflect.Ptr && retValue.Kind() != reflect.Struct {
- return zero, fserr.New("返回类型不是结构或结构指针")
- }
- if retValue.Kind() == reflect.Ptr && retValue.Elem().Kind() != reflect.Struct {
- return zero, fserr.New("返回类型不是结构或结构指针")
- }
- fromElemValue := fromValue
- if fromValue.Kind() == reflect.Ptr {
- fromElemValue = fromValue.Elem()
- }
- retElemValue := retValue
- if retValue.Kind() == reflect.Ptr {
- retElemValue = retValue.Elem()
- }
- err := assignTo(fromElemValue, &retElemValue)
- if err != nil {
- return zero, err
- }
- return retValue.Interface().(T), nil
- }
- func assignTo(fromElemValue reflect.Value, retElemValue *reflect.Value) error {
- for i := 0; i < fromElemValue.NumField(); i++ {
- fromField := fromElemValue.Type().Field(i)
- tagStr := fromField.Tag.Get(assignTagKey)
- // 结构上没有添加Tag, 先尝试直接按照字段赋值结构,如果失败,进一步进入内部尝试
- if strutils.IsStringEmpty(tagStr) &&
- ((fromField.Type.Kind() == reflect.Struct && fromField.Type.String() != "time.Time") ||
- (fromField.Type.Kind() == reflect.Ptr &&
- fromField.Type.Elem().Kind() == reflect.Struct &&
- fromField.Type.Elem().String() != "time.Time")) {
- fromStructElemValue := fromElemValue.Field(i)
- if fromField.Type.Kind() == reflect.Ptr {
- if !fromStructElemValue.IsValid() || fromStructElemValue.IsZero() {
- continue
- }
- fromStructElemValue = fromStructElemValue.Elem()
- }
- err := assignTo(fromStructElemValue, retElemValue)
- if err != nil {
- return err
- }
- }
- tag, err := parseAssignTag(fromField, tagStr)
- if err != nil {
- return err
- }
- if tag == nil {
- continue
- }
- fromFieldValue := fromElemValue.Field(i)
- // 无效零值,不进行赋值
- if !fromFieldValue.IsValid() || fromFieldValue.IsZero() {
- continue
- }
- fromFieldElemValue := fromFieldValue
- if fromFieldValue.Kind() == reflect.Ptr {
- fromFieldElemValue = fromFieldValue.Elem()
- }
- retFieldValue := retElemValue.FieldByName(tag.ToField)
- // 不存在对应的字段
- if !retFieldValue.IsValid() {
- continue
- }
- retFieldElemValue := retFieldValue
- if retFieldValue.Kind() == reflect.Ptr {
- if !retFieldValue.IsValid() {
- continue
- }
- if !retFieldValue.CanSet() {
- continue
- }
- // 空值针,初始化
- if retFieldValue.IsNil() {
- retFieldValue.Set(reflect.New(retFieldValue.Type().Elem()))
- }
- retFieldElemValue = retFieldValue.Elem()
- }
- err = assignField(fromFieldElemValue, retFieldElemValue, tag)
- if err != nil {
- return err
- }
- }
- return nil
- }
- func assignField(fromFieldElemValue reflect.Value, retFieldElemValue reflect.Value, tag *assignTag) error {
- fromKind := reflectutils.GroupValueKind(fromFieldElemValue)
- retKind := reflectutils.GroupValueKind(retFieldElemValue)
- var fromAny any
- switch fromKind {
- case reflect.Struct:
- if fromFieldElemValue.Type().String() == "time.Time" && retKind == reflect.String {
- fromString := fromFieldElemValue.Interface().(time.Time).Format(tag.FormatTime)
- fromAny = trimFromString(fromString, tag)
- break
- }
- if fromFieldElemValue.Type().String() != "time.Time" && retKind == reflect.Struct {
- return assignTo(fromFieldElemValue, &retFieldElemValue)
- }
- fromAny = fromFieldElemValue.Interface()
- case reflect.Slice:
- if fromFieldElemValue.Elem().Kind() == reflect.String && retKind == reflect.String {
- fromString := strings.Join(fromFieldElemValue.Interface().([]string), tag.JoinWith)
- fromAny = trimFromString(fromString, tag)
- break
- }
- fromAny = fromFieldElemValue.Interface()
- case reflect.String:
- fromString := fromFieldElemValue.String()
- if retKind == reflect.Struct && retFieldElemValue.Type().String() == "time.Time" {
- retTimeField, err := time.ParseInLocation(tag.ParseTime, fromString, time.Local)
- if err != nil {
- return err
- }
- fromAny = retTimeField
- break
- }
- if retFieldElemValue.Kind() == reflect.Slice && retFieldElemValue.Elem().Kind() == reflect.String {
- fromAny = strings.Split(fromString, tag.SplitWith)
- break
- }
- fromAny = trimFromString(fromString, tag)
- default:
- fromAny = fromFieldElemValue.Interface()
- }
- switch retKind {
- case reflect.Int64:
- return reflectutils.AssignInt64Value(fromAny, retFieldElemValue)
- case reflect.Uint64:
- return reflectutils.AssignUint64Value(fromAny, retFieldElemValue)
- case reflect.Float64:
- return reflectutils.AssignFloat64Value(fromAny, retFieldElemValue)
- case reflect.Bool:
- return reflectutils.AssignBoolValue(fromAny, retFieldElemValue)
- case reflect.String:
- return reflectutils.AssignStringValue(fromAny, retFieldElemValue)
- default:
- retFieldElemValue.Set(reflect.ValueOf(fromAny))
- return nil
- }
- }
- func trimFromString(fromString string, tag *assignTag) string {
- if strutils.IsStringNotEmpty(tag.Trim) {
- return strings.Trim(fromString, tag.Trim)
- } else {
- if strutils.IsStringNotEmpty(tag.TrimPrefix) {
- return strings.TrimPrefix(fromString, tag.TrimPrefix)
- }
- if strutils.IsStringNotEmpty(tag.TrimSuffix) {
- return strings.TrimSuffix(fromString, tag.TrimSuffix)
- }
- }
- return fromString
- }
- const (
- assignDefaultStringSliceSeparator = "::"
- assignTagPartSeparator = ";"
- assignTagPartKeyValueSeparator = ":"
- )
- const (
- assignTagKey = "assign"
- assignIgnore = "-"
- assignToField = "toField"
- assignParseTime = "parseTime"
- assignFormatTime = "formatTime"
- assignJoinWith = "joinWith"
- assignSplitWith = "splitWith"
- assignTrim = "trim"
- assignTrimPrefix = "trimPrefix"
- assignTrimSuffix = "trimSuffix"
- )
- type assignTag struct {
- ToField string
- ParseTime string
- FormatTime string
- JoinWith string
- SplitWith string
- Trim string
- TrimPrefix string
- TrimSuffix string
- }
- func parseAssignTag(field reflect.StructField, tagStr string) (*assignTag, error) {
- if tagStr == assignIgnore {
- return nil, nil
- }
- tag := &assignTag{
- ToField: field.Name,
- ParseTime: time.DateTime,
- FormatTime: time.DateTime,
- JoinWith: assignDefaultStringSliceSeparator,
- SplitWith: assignDefaultStringSliceSeparator,
- Trim: "",
- TrimPrefix: "",
- TrimSuffix: "",
- }
- if strutils.IsStringEmpty(tagStr) {
- return tag, nil
- }
- assignParts := strings.Split(tagStr, assignTagPartSeparator)
- if assignParts != nil || len(assignParts) != 0 {
- for _, assignPart := range assignParts {
- assignPartKeyValue := strings.SplitN(strings.TrimSpace(assignPart), assignTagPartKeyValueSeparator, 2)
- if assignPartKeyValue != nil && len(assignPartKeyValue) == 2 && strutils.IsStringNotEmpty(assignPartKeyValue[1]) {
- // 可以支持' ' ',获取到'字符
- assignPartKeyValue[1] = strings.TrimSpace(strings.Trim(assignPartKeyValue[1], "'"))
- }
- switch assignPartKeyValue[0] {
- case assignToField:
- tag.ToField = assignPartKeyValue[1]
- case assignParseTime:
- tag.ParseTime = assignPartKeyValue[1]
- case assignFormatTime:
- tag.FormatTime = assignPartKeyValue[1]
- case assignJoinWith:
- if strutils.IsStringEmpty(assignPartKeyValue[1]) {
- return nil, fserr.New(assignJoinWith + "没有赋值分隔符")
- }
- tag.JoinWith = assignPartKeyValue[1]
- case assignSplitWith:
- if strutils.IsStringEmpty(assignPartKeyValue[1]) {
- return nil, fserr.New(assignSplitWith + "没有赋值分隔符")
- }
- tag.SplitWith = assignPartKeyValue[1]
- case assignTrim:
- tag.Trim = assignPartKeyValue[1]
- case assignTrimPrefix:
- tag.TrimPrefix = assignPartKeyValue[1]
- case assignTrimSuffix:
- tag.TrimSuffix = assignPartKeyValue[1]
- default:
- err := fserr.New(assignTagKey + "不支持的tag: " + assignPartKeyValue[0])
- fslog.Error(err)
- continue
- }
- }
- }
- return tag, nil
- }
|