structs_field.go 4.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158
  1. // Copyright GoFrame Author(https://goframe.org). All Rights Reserved.
  2. //
  3. // This Source Code Form is subject to the terms of the MIT License.
  4. // If a copy of the MIT was not distributed with this file,
  5. // You can obtain one at https://github.com/gogf/gf.
  6. package structs
  7. import "reflect"
  8. // Tag returns the value associated with key in the tag string. If there is no
  9. // such key in the tag, Tag returns the empty string.
  10. func (f *Field) Tag(key string) string {
  11. return f.Field.Tag.Get(key)
  12. }
  13. // TagLookup returns the value associated with key in the tag string.
  14. // If the key is present in the tag the value (which may be empty)
  15. // is returned. Otherwise, the returned value will be the empty string.
  16. // The ok return value reports whether the value was explicitly set in
  17. // the tag string. If the tag does not have the conventional format,
  18. // the value returned by Lookup is unspecified.
  19. func (f *Field) TagLookup(key string) (value string, ok bool) {
  20. return f.Field.Tag.Lookup(key)
  21. }
  22. // IsEmbedded returns true if the given field is an anonymous field (embedded)
  23. func (f *Field) IsEmbedded() bool {
  24. return f.Field.Anonymous
  25. }
  26. // TagStr returns the tag string of the field.
  27. func (f *Field) TagStr() string {
  28. return string(f.Field.Tag)
  29. }
  30. // IsExported returns true if the given field is exported.
  31. func (f *Field) IsExported() bool {
  32. return f.Field.PkgPath == ""
  33. }
  34. // Name returns the name of the given field
  35. func (f *Field) Name() string {
  36. return f.Field.Name
  37. }
  38. // Type returns the type of the given field
  39. func (f *Field) Type() Type {
  40. return Type{
  41. Type: f.Field.Type,
  42. }
  43. }
  44. // Kind returns the reflect.Kind for Value of Field `f`.
  45. func (f *Field) Kind() reflect.Kind {
  46. return f.Value.Kind()
  47. }
  48. // OriginalKind retrieves and returns the original reflect.Kind for Value of Field `f`.
  49. func (f *Field) OriginalKind() reflect.Kind {
  50. var (
  51. kind = f.Value.Kind()
  52. value = f.Value
  53. )
  54. for kind == reflect.Ptr {
  55. value = value.Elem()
  56. kind = value.Kind()
  57. }
  58. return kind
  59. }
  60. const (
  61. RecursiveOptionNone = 0 // No recursively retrieving fields as map if the field is an embedded struct.
  62. RecursiveOptionEmbedded = 1 // Recursively retrieving fields as map if the field is an embedded struct.
  63. RecursiveOptionEmbeddedNoTag = 2 // Recursively retrieving fields as map if the field is an embedded struct and the field has no tag.
  64. )
  65. type FieldMapInput struct {
  66. // Pointer should be type of struct/*struct.
  67. Pointer interface{}
  68. // PriorityTagArray specifies the priority tag array for retrieving from high to low.
  69. // If it's given `nil`, it returns map[name]*Field, of which the `name` is attribute name.
  70. PriorityTagArray []string
  71. // RecursiveOption specifies the way retrieving the fields recursively if the attribute
  72. // is an embedded struct. It is RecursiveOptionNone in default.
  73. RecursiveOption int
  74. }
  75. // FieldMap retrieves and returns struct field as map[name/tag]*Field from `pointer`.
  76. //
  77. // The parameter `pointer` should be type of struct/*struct.
  78. //
  79. // The parameter `priority` specifies the priority tag array for retrieving from high to low.
  80. // If it's given `nil`, it returns map[name]*Field, of which the `name` is attribute name.
  81. //
  82. // The parameter `recursive` specifies the whether retrieving the fields recursively if the attribute
  83. // is an embedded struct.
  84. //
  85. // Note that it only retrieves the exported attributes with first letter up-case from struct.
  86. func FieldMap(input FieldMapInput) (map[string]*Field, error) {
  87. fields, err := getFieldValues(input.Pointer)
  88. if err != nil {
  89. return nil, err
  90. }
  91. var (
  92. tagValue = ""
  93. mapField = make(map[string]*Field)
  94. )
  95. for _, field := range fields {
  96. // Only retrieve exported attributes.
  97. if !field.IsExported() {
  98. continue
  99. }
  100. tagValue = ""
  101. for _, p := range input.PriorityTagArray {
  102. tagValue = field.Tag(p)
  103. if tagValue != "" && tagValue != "-" {
  104. break
  105. }
  106. }
  107. tempField := field
  108. tempField.TagValue = tagValue
  109. if tagValue != "" {
  110. mapField[tagValue] = tempField
  111. } else {
  112. if input.RecursiveOption != RecursiveOptionNone && field.IsEmbedded() {
  113. switch input.RecursiveOption {
  114. case RecursiveOptionEmbeddedNoTag:
  115. if field.TagStr() != "" {
  116. mapField[field.Name()] = tempField
  117. break
  118. }
  119. fallthrough
  120. case RecursiveOptionEmbedded:
  121. m, err := FieldMap(FieldMapInput{
  122. Pointer: field.Value,
  123. PriorityTagArray: input.PriorityTagArray,
  124. RecursiveOption: input.RecursiveOption,
  125. })
  126. if err != nil {
  127. return nil, err
  128. }
  129. for k, v := range m {
  130. if _, ok := mapField[k]; !ok {
  131. tempV := v
  132. mapField[k] = tempV
  133. }
  134. }
  135. }
  136. } else {
  137. mapField[field.Name()] = tempField
  138. }
  139. }
  140. }
  141. return mapField, nil
  142. }