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