Documentation ¶
Overview ¶
Package reflections provides high level abstractions over the Go standard reflect library.
In practice, the `reflect` library's API proves somewhat low-level and un-intuitive. Using it can turn out pretty complex, daunting, and scary, when doing simple things like accessing a structure field value, a field tag, etc.
The `reflections` package aims to make developers' life easier when it comes to introspect struct values at runtime. Its API takes inspiration in the python language's `getattr,` `setattr,` and `hasattr` set of methods and provides simplified access to structure fields and tags.
Index ¶
- Variables
- func Fields(obj interface{}) ([]string, error)
- func FieldsDeep(obj interface{}) ([]string, error)
- func GetField(obj interface{}, name string) (interface{}, error)
- func GetFieldKind(obj interface{}, name string) (reflect.Kind, error)
- func GetFieldNameByTagValue(obj interface{}, tagKey, tagValue string) (string, error)
- func GetFieldTag(obj interface{}, fieldName, tagKey string) (string, error)
- func GetFieldType(obj interface{}, name string) (string, error)
- func HasField(obj interface{}, name string) (bool, error)
- func Items(obj interface{}) (map[string]interface{}, error)
- func ItemsDeep(obj interface{}) (map[string]interface{}, error)
- func SetField(obj interface{}, name string, value interface{}) error
- func Tags(obj interface{}, key string) (map[string]string, error)
- func TagsDeep(obj interface{}, key string) (map[string]string, error)
Examples ¶
Constants ¶
This section is empty.
Variables ¶
var ErrUnexportedField = errors.New("unexported field")
ErrUnexportedField indicates that an operation failed as a result of applying to a non-exported struct field.
var ErrUnsupportedType = errors.New("unsupported type")
ErrUnsupportedType indicates that the provided type doesn't support the requested reflection operation.
Functions ¶
func Fields ¶
Fields returns the struct fields names list. The `obj` parameter can either be a structure or pointer to structure.
Example ¶
package main import ( "fmt" "github.com/oleiade/reflections" ) type MyStruct struct { MyEmbeddedStruct FirstField string `matched:"first tag"` SecondField int `matched:"second tag"` ThirdField string `unmatched:"third tag"` } type MyEmbeddedStruct struct { EmbeddedField string } func main() { s := MyStruct{ FirstField: "first value", SecondField: 2, ThirdField: "third value", } var fields []string // Fields will list every structure exportable fields. // Here, it's content would be equal to: // []string{"FirstField", "SecondField", "ThirdField"} fields, _ = reflections.Fields(s) fmt.Println(fields) }
Output: [MyEmbeddedStruct FirstField SecondField ThirdField]
func FieldsDeep ¶
FieldsDeep returns "flattened" fields.
Note that FieldsDeep treats fields from anonymous inner structs as normal fields.
func GetField ¶
GetField returns the value of the provided obj field. The `obj` can either be a structure or pointer to structure.
Example ¶
package main import ( "fmt" "log" "github.com/oleiade/reflections" ) type MyStruct struct { MyEmbeddedStruct FirstField string `matched:"first tag"` SecondField int `matched:"second tag"` ThirdField string `unmatched:"third tag"` } type MyEmbeddedStruct struct { EmbeddedField string } func main() { s := MyStruct{ FirstField: "first value", SecondField: 2, ThirdField: "third value", } fieldsToExtract := []string{"FirstField", "ThirdField"} for _, fieldName := range fieldsToExtract { value, err := reflections.GetField(s, fieldName) if err != nil { log.Fatal(err) } fmt.Println(value) } }
Output: first value third value
func GetFieldKind ¶
GetFieldKind returns the kind of the provided obj field. The `obj` can either be a structure or pointer to structure.
Example ¶
package main import ( "fmt" "log" "reflect" "github.com/oleiade/reflections" ) type MyStruct struct { MyEmbeddedStruct FirstField string `matched:"first tag"` SecondField int `matched:"second tag"` ThirdField string `unmatched:"third tag"` } type MyEmbeddedStruct struct { EmbeddedField string } func main() { s := MyStruct{ FirstField: "first value", SecondField: 2, ThirdField: "third value", } var firstFieldKind reflect.Kind var secondFieldKind reflect.Kind var err error // GetFieldKind will return reflect.String firstFieldKind, err = reflections.GetFieldKind(s, "FirstField") if err != nil { log.Fatal(err) } fmt.Println(firstFieldKind) // GetFieldKind will return reflect.Int secondFieldKind, err = reflections.GetFieldKind(s, "SecondField") if err != nil { log.Fatal(err) } fmt.Println(secondFieldKind) }
Output: string int
func GetFieldNameByTagValue ¶ added in v1.1.0
GetFieldNameByTagValue looks up a field with a matching `{tagKey}:"{tagValue}"` tag in the provided `obj` item. The `obj` parameter must be a `struct`, or a `pointer` to one. If the `obj` parameter doesn't have a field tagged with the `tagKey`, and the matching `tagValue`, this function returns an error.
Example ¶
package main import ( "encoding/json" "fmt" "log" "github.com/oleiade/reflections" ) func main() { type Order struct { Step string `json:"order_step"` ID string `json:"id"` Category string `json:"category"` } type Condition struct { Field string `json:"field"` Value string `json:"value"` Next string `json:"next"` } // JSON data from external source orderJSON := `{ "order_step": "cooking", "id": "45457-fv54f54", "category": "Pizzas" }` conditionJSON := `{ "field": "order_step", "value": "cooking", "next": "serve" }` // Storing JSON in corresponding Variables var order Order err := json.Unmarshal([]byte(orderJSON), &order) if err != nil { log.Fatal(err) } var condition Condition err = json.Unmarshal([]byte(conditionJSON), &condition) if err != nil { log.Fatal(err) } fieldName, _ := reflections.GetFieldNameByTagValue(order, "json", condition.Field) fmt.Println(fieldName) fieldValue, _ := reflections.GetField(order, fieldName) fmt.Println(fieldValue) }
Output: Step cooking
func GetFieldTag ¶
GetFieldTag returns the provided obj field tag value. The `obj` parameter can either be a structure or pointer to structure.
Example ¶
package main import ( "fmt" "log" "github.com/oleiade/reflections" ) type MyStruct struct { MyEmbeddedStruct FirstField string `matched:"first tag"` SecondField int `matched:"second tag"` ThirdField string `unmatched:"third tag"` } type MyEmbeddedStruct struct { EmbeddedField string } func main() { s := MyStruct{} tag, err := reflections.GetFieldTag(s, "FirstField", "matched") if err != nil { log.Fatal(err) } fmt.Println(tag) tag, err = reflections.GetFieldTag(s, "ThirdField", "unmatched") if err != nil { log.Fatal(err) } fmt.Println(tag) }
Output: first tag third tag
func GetFieldType ¶ added in v1.0.1
GetFieldType returns the kind of the provided obj field. The `obj` can either be a structure or pointer to structure.
Example ¶
package main import ( "fmt" "log" "github.com/oleiade/reflections" ) type MyStruct struct { MyEmbeddedStruct FirstField string `matched:"first tag"` SecondField int `matched:"second tag"` ThirdField string `unmatched:"third tag"` } type MyEmbeddedStruct struct { EmbeddedField string } func main() { s := MyStruct{ FirstField: "first value", SecondField: 2, ThirdField: "third value", } var firstFieldType string var secondFieldType string var err error // GetFieldType will return reflect.String firstFieldType, err = reflections.GetFieldType(s, "FirstField") if err != nil { log.Fatal(err) } fmt.Println(firstFieldType) // GetFieldType will return reflect.Int secondFieldType, err = reflections.GetFieldType(s, "SecondField") if err != nil { log.Fatal(err) } fmt.Println(secondFieldType) }
Output: string int
func HasField ¶
HasField checks if the provided `obj` struct has field named `name`. The `obj` can either be a structure or pointer to structure.
Example ¶
package main import ( "fmt" "github.com/oleiade/reflections" ) type MyStruct struct { MyEmbeddedStruct FirstField string `matched:"first tag"` SecondField int `matched:"second tag"` ThirdField string `unmatched:"third tag"` } type MyEmbeddedStruct struct { EmbeddedField string } func main() { s := MyStruct{ FirstField: "first value", SecondField: 2, ThirdField: "third value", } // has == true has, _ := reflections.HasField(s, "FirstField") fmt.Println(has) // has == false has, _ = reflections.HasField(s, "FourthField") fmt.Println(has) }
Output: true false
func Items ¶
Items returns the field:value struct pairs as a map. The `obj` parameter can either be a structure or pointer to structure.
Example ¶
package main import ( "fmt" "github.com/oleiade/reflections" ) type MyStruct struct { MyEmbeddedStruct FirstField string `matched:"first tag"` SecondField int `matched:"second tag"` ThirdField string `unmatched:"third tag"` } type MyEmbeddedStruct struct { EmbeddedField string } func main() { s := MyStruct{ FirstField: "first value", SecondField: 2, ThirdField: "third value", } var structItems map[string]interface{} // Items will return a field name to // field value map structItems, _ = reflections.Items(s) fmt.Println(structItems) }
Output: map[FirstField:first value MyEmbeddedStruct:{} SecondField:2 ThirdField:third value]
func ItemsDeep ¶
ItemsDeep returns "flattened" items. Note that ItemsDeep will treat fields from anonymous inner structs as normal fields.
Example ¶
package main import ( "fmt" "github.com/oleiade/reflections" ) type MyStruct struct { MyEmbeddedStruct FirstField string `matched:"first tag"` SecondField int `matched:"second tag"` ThirdField string `unmatched:"third tag"` } type MyEmbeddedStruct struct { EmbeddedField string } func main() { s := MyStruct{ FirstField: "first value", SecondField: 2, ThirdField: "third value", MyEmbeddedStruct: MyEmbeddedStruct{ EmbeddedField: "embedded value", }, } var structItems map[string]interface{} // ItemsDeep will return a field name to // field value map, including fields from // anonymous embedded structs structItems, _ = reflections.ItemsDeep(s) fmt.Println(structItems) }
Output: map[EmbeddedField:embedded value FirstField:first value SecondField:2 ThirdField:third value]
func SetField ¶
SetField sets the provided obj field with provided value.
The `obj` parameter must be a pointer to a struct, otherwise it soundly fails. The provided `value` type should match with the struct field being set.
Example ¶
package main import ( "log" "github.com/oleiade/reflections" ) type MyStruct struct { MyEmbeddedStruct FirstField string `matched:"first tag"` SecondField int `matched:"second tag"` ThirdField string `unmatched:"third tag"` } type MyEmbeddedStruct struct { EmbeddedField string } func main() { s := MyStruct{ FirstField: "first value", SecondField: 2, ThirdField: "third value", } // In order to be able to set the structure's values, // a pointer to it has to be passed to it. err := reflections.SetField(&s, "FirstField", "new value") if err != nil { log.Fatal(err) } // Note that if you try to set a field's value using the wrong type, // an error will be returned _ = reflections.SetField(&s, "FirstField", 123) // err != nil }
Output:
func Tags ¶
Tags lists the struct tag fields. The `obj` can whether be a structure or pointer to structure.
Example ¶
package main import ( "fmt" "github.com/oleiade/reflections" ) type MyStruct struct { MyEmbeddedStruct FirstField string `matched:"first tag"` SecondField int `matched:"second tag"` ThirdField string `unmatched:"third tag"` } type MyEmbeddedStruct struct { EmbeddedField string } func main() { s := MyStruct{ FirstField: "first value", SecondField: 2, ThirdField: "third value", } var structTags map[string]string // Tags will return a field name to tag content // map. Nota that only field with the tag name // you've provided which will be matched. // Here structTags will contain: // { // "FirstField": "first tag", // "SecondField": "second tag", // } structTags, _ = reflections.Tags(s, "matched") fmt.Println(structTags) }
Output: map[FirstField:first tag MyEmbeddedStruct: SecondField:second tag ThirdField:]
Types ¶
This section is empty.