assign_struct.go 8.4 KB

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