assign_struct.go 7.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280
  1. package tag
  2. import (
  3. "git.sxidc.com/go-tools/utils/reflectutils"
  4. "git.sxidc.com/go-tools/utils/strutils"
  5. "git.sxidc.com/service-supports/fserr"
  6. "git.sxidc.com/service-supports/fslog"
  7. "reflect"
  8. "strings"
  9. "time"
  10. )
  11. func AssignTo[T any](from any) (T, error) {
  12. var zero T
  13. if from == nil {
  14. return zero, nil
  15. }
  16. fromValue := reflect.ValueOf(from)
  17. retValue := reflect.ValueOf(zero)
  18. // 类型校验
  19. if fromValue.Kind() != reflect.Ptr && fromValue.Kind() != reflect.Struct {
  20. return zero, fserr.New("参数不是结构或结构指针")
  21. }
  22. if fromValue.Kind() == reflect.Ptr && fromValue.Kind() != reflect.Struct {
  23. return zero, fserr.New("参数不是结构或结构指针")
  24. }
  25. if retValue.Kind() != reflect.Ptr && retValue.Kind() != reflect.Struct {
  26. return zero, fserr.New("返回类型不是结构或结构指针")
  27. }
  28. if retValue.Kind() == reflect.Ptr && retValue.Elem().Kind() != reflect.Struct {
  29. return zero, fserr.New("返回类型不是结构或结构指针")
  30. }
  31. fromElemValue := fromValue
  32. if fromValue.Kind() == reflect.Ptr {
  33. fromElemValue = fromValue.Elem()
  34. }
  35. retElemValue := retValue
  36. if retValue.Kind() == reflect.Ptr {
  37. retElemValue = retValue.Elem()
  38. }
  39. for i := 0; i < fromElemValue.NumField(); i++ {
  40. fromField := fromElemValue.Type().Field(i)
  41. tag, err := parseAssignTag(fromField)
  42. if err != nil {
  43. return zero, err
  44. }
  45. if tag == nil {
  46. continue
  47. }
  48. fromFieldValue := fromElemValue.Field(i)
  49. // 无效零值,不进行赋值
  50. if !fromFieldValue.IsValid() || fromFieldValue.IsNil() || fromFieldValue.IsZero() {
  51. continue
  52. }
  53. fromFieldElemValue := fromFieldValue
  54. if fromFieldValue.Kind() == reflect.Ptr {
  55. fromFieldElemValue = fromFieldValue.Elem()
  56. }
  57. retFieldValue := retElemValue.FieldByName(tag.ToField)
  58. // 不存在对应的字段
  59. if !retFieldValue.IsValid() {
  60. continue
  61. }
  62. retFieldElemValue := retFieldValue
  63. if retFieldValue.Kind() == reflect.Ptr {
  64. if !retFieldValue.IsValid() {
  65. continue
  66. }
  67. if !retFieldValue.CanSet() {
  68. continue
  69. }
  70. // 空值针,初始化
  71. if retFieldValue.IsNil() {
  72. retFieldValue.Set(reflect.New(retFieldValue.Type().Elem()))
  73. }
  74. retFieldElemValue = retFieldValue.Elem()
  75. }
  76. err = assignTo(fromFieldElemValue, retFieldElemValue, tag)
  77. if err != nil {
  78. return zero, err
  79. }
  80. }
  81. return retValue.Interface(), nil
  82. }
  83. func assignTo(fromFieldElemValue reflect.Value, retFieldElemValue reflect.Value, tag *assignTag) error {
  84. fromKind := reflectutils.GroupValueKind(fromFieldElemValue)
  85. retKind := reflectutils.GroupValueKind(retFieldElemValue)
  86. var fromAny any
  87. switch fromKind {
  88. case reflect.Struct:
  89. if fromFieldElemValue.Type().String() == "time.Time" && retKind == reflect.String {
  90. fromString := fromFieldElemValue.Interface().(time.Time).Format(tag.FormatTime)
  91. fromAny = trimFromString(fromString, tag)
  92. break
  93. }
  94. fromAny = fromFieldElemValue.Interface()
  95. case reflect.Slice:
  96. if fromFieldElemValue.Elem().Kind() == reflect.String && retKind == reflect.String {
  97. fromString := strings.Join(fromFieldElemValue.Interface().([]string), tag.JoinWith)
  98. fromAny = trimFromString(fromString, tag)
  99. break
  100. }
  101. fromAny = fromFieldElemValue.Interface()
  102. case reflect.String:
  103. fromString := fromFieldElemValue.String()
  104. if retKind == reflect.Struct && retFieldElemValue.Type().String() == "time.Time" {
  105. retTimeField, err := time.ParseInLocation(tag.ParseTime, fromString, time.Local)
  106. if err != nil {
  107. return err
  108. }
  109. fromAny = retTimeField
  110. break
  111. }
  112. if retFieldElemValue.Kind() == reflect.Slice && retFieldElemValue.Elem().Kind() == reflect.String {
  113. fromAny = strings.Split(fromString, tag.SplitWith)
  114. break
  115. }
  116. fromAny = trimFromString(fromString, tag)
  117. default:
  118. fromAny = fromFieldElemValue.Interface()
  119. }
  120. switch retKind {
  121. case reflect.Int64:
  122. return reflectutils.AssignInt64Value(fromAny, retFieldElemValue)
  123. case reflect.Uint64:
  124. return reflectutils.AssignUint64Value(fromAny, retFieldElemValue)
  125. case reflect.Float64:
  126. return reflectutils.AssignFloat64Value(fromAny, retFieldElemValue)
  127. case reflect.Bool:
  128. return reflectutils.AssignBoolValue(fromAny, retFieldElemValue)
  129. case reflect.String:
  130. return reflectutils.AssignStringValue(fromAny, retFieldElemValue)
  131. default:
  132. retFieldElemValue.Set(reflect.ValueOf(fromAny))
  133. return nil
  134. }
  135. }
  136. func trimFromString(fromString string, tag *assignTag) string {
  137. if strutils.IsStringNotEmpty(tag.Trim) {
  138. return strings.Trim(fromString, tag.Trim)
  139. } else {
  140. if strutils.IsStringNotEmpty(tag.TrimPrefix) {
  141. return strings.TrimPrefix(fromString, tag.TrimPrefix)
  142. }
  143. if strutils.IsStringNotEmpty(tag.TrimSuffix) {
  144. return strings.TrimSuffix(fromString, tag.TrimSuffix)
  145. }
  146. }
  147. return fromString
  148. }
  149. const (
  150. assignDefaultStringSliceSeparator = "::"
  151. assignTagPartSeparator = ";"
  152. assignTagPartKeyValueSeparator = ":"
  153. )
  154. const (
  155. assignTagKey = "assign"
  156. assignIgnore = "-"
  157. assignToField = "toField"
  158. assignParseTime = "parseTime"
  159. assignFormatTime = "formatTime"
  160. assignJoinWith = "joinWith"
  161. assignSplitWith = "splitWith"
  162. assignTrim = "trim"
  163. assignTrimPrefix = "trimPrefix"
  164. assignTrimSuffix = "trimSuffix"
  165. )
  166. type assignTag struct {
  167. ToField string
  168. ParseTime string
  169. FormatTime string
  170. JoinWith string
  171. SplitWith string
  172. Trim string
  173. TrimPrefix string
  174. TrimSuffix string
  175. }
  176. func parseAssignTag(field reflect.StructField) (*assignTag, error) {
  177. tagStr := field.Tag.Get(assignTagKey)
  178. if tagStr == assignIgnore {
  179. return nil, nil
  180. }
  181. tag := &assignTag{
  182. ToField: field.Name,
  183. ParseTime: time.DateTime,
  184. FormatTime: time.DateTime,
  185. JoinWith: assignDefaultStringSliceSeparator,
  186. SplitWith: assignDefaultStringSliceSeparator,
  187. Trim: "",
  188. TrimPrefix: "",
  189. TrimSuffix: "",
  190. }
  191. if strutils.IsStringEmpty(tagStr) {
  192. return tag, nil
  193. }
  194. assignParts := strings.Split(tagStr, assignTagPartSeparator)
  195. if assignParts != nil || len(assignParts) != 0 {
  196. for _, assignPart := range assignParts {
  197. assignPartKeyValue := strings.SplitN(strings.TrimSpace(assignPart), assignTagPartKeyValueSeparator, 2)
  198. if assignPartKeyValue != nil && len(assignPartKeyValue) == 2 && strutils.IsStringNotEmpty(assignPartKeyValue[1]) {
  199. // 可以支持' ' ',获取到'字符
  200. assignPartKeyValue[1] = strings.TrimSpace(strings.Trim(assignPartKeyValue[1], "'"))
  201. }
  202. switch assignPartKeyValue[0] {
  203. case assignToField:
  204. tag.ToField = assignPartKeyValue[1]
  205. case assignParseTime:
  206. tag.ParseTime = assignPartKeyValue[1]
  207. case assignFormatTime:
  208. tag.FormatTime = assignPartKeyValue[1]
  209. case assignJoinWith:
  210. if strutils.IsStringEmpty(assignPartKeyValue[1]) {
  211. return nil, fserr.New(assignJoinWith + "没有赋值分隔符")
  212. }
  213. tag.JoinWith = assignPartKeyValue[1]
  214. case assignSplitWith:
  215. if strutils.IsStringEmpty(assignPartKeyValue[1]) {
  216. return nil, fserr.New(assignSplitWith + "没有赋值分隔符")
  217. }
  218. tag.SplitWith = assignPartKeyValue[1]
  219. case assignTrim:
  220. tag.Trim = assignPartKeyValue[1]
  221. case assignTrimPrefix:
  222. tag.TrimPrefix = assignPartKeyValue[1]
  223. case assignTrimSuffix:
  224. tag.TrimSuffix = assignPartKeyValue[1]
  225. default:
  226. err := fserr.New(assignTagKey + "不支持的tag: " + assignPartKeyValue[0])
  227. fslog.Error(err)
  228. continue
  229. }
  230. }
  231. }
  232. return tag, nil
  233. }