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
}
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.