field.go 3.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141
  1. package structs
  2. import (
  3. "errors"
  4. "fmt"
  5. "reflect"
  6. )
  7. var (
  8. errNotExported = errors.New("field is not exported")
  9. errNotSettable = errors.New("field is not settable")
  10. )
  11. // Field represents a single struct field that encapsulates high level
  12. // functions around the field.
  13. type Field struct {
  14. value reflect.Value
  15. field reflect.StructField
  16. defaultTag string
  17. }
  18. // Tag returns the value associated with key in the tag string. If there is no
  19. // such key in the tag, Tag returns the empty string.
  20. func (f *Field) Tag(key string) string {
  21. return f.field.Tag.Get(key)
  22. }
  23. // Value returns the underlying value of the field. It panics if the field
  24. // is not exported.
  25. func (f *Field) Value() interface{} {
  26. return f.value.Interface()
  27. }
  28. // IsEmbedded returns true if the given field is an anonymous field (embedded)
  29. func (f *Field) IsEmbedded() bool {
  30. return f.field.Anonymous
  31. }
  32. // IsExported returns true if the given field is exported.
  33. func (f *Field) IsExported() bool {
  34. return f.field.PkgPath == ""
  35. }
  36. // IsZero returns true if the given field is not initialized (has a zero value).
  37. // It panics if the field is not exported.
  38. func (f *Field) IsZero() bool {
  39. zero := reflect.Zero(f.value.Type()).Interface()
  40. current := f.Value()
  41. return reflect.DeepEqual(current, zero)
  42. }
  43. // Name returns the name of the given field
  44. func (f *Field) Name() string {
  45. return f.field.Name
  46. }
  47. // Kind returns the fields kind, such as "string", "map", "bool", etc ..
  48. func (f *Field) Kind() reflect.Kind {
  49. return f.value.Kind()
  50. }
  51. // Set sets the field to given value v. It returns an error if the field is not
  52. // settable (not addressable or not exported) or if the given value's type
  53. // doesn't match the fields type.
  54. func (f *Field) Set(val interface{}) error {
  55. // we can't set unexported fields, so be sure this field is exported
  56. if !f.IsExported() {
  57. return errNotExported
  58. }
  59. // do we get here? not sure...
  60. if !f.value.CanSet() {
  61. return errNotSettable
  62. }
  63. given := reflect.ValueOf(val)
  64. if f.value.Kind() != given.Kind() {
  65. return fmt.Errorf("wrong kind. got: %s want: %s", given.Kind(), f.value.Kind())
  66. }
  67. f.value.Set(given)
  68. return nil
  69. }
  70. // Zero sets the field to its zero value. It returns an error if the field is not
  71. // settable (not addressable or not exported).
  72. func (f *Field) Zero() error {
  73. zero := reflect.Zero(f.value.Type()).Interface()
  74. return f.Set(zero)
  75. }
  76. // Fields returns a slice of Fields. This is particular handy to get the fields
  77. // of a nested struct . A struct tag with the content of "-" ignores the
  78. // checking of that particular field. Example:
  79. //
  80. // // Field is ignored by this package.
  81. // Field *http.Request `structs:"-"`
  82. //
  83. // It panics if field is not exported or if field's kind is not struct
  84. func (f *Field) Fields() []*Field {
  85. return getFields(f.value, f.defaultTag)
  86. }
  87. // Field returns the field from a nested struct. It panics if the nested struct
  88. // is not exported or if the field was not found.
  89. func (f *Field) Field(name string) *Field {
  90. field, ok := f.FieldOk(name)
  91. if !ok {
  92. panic("field not found")
  93. }
  94. return field
  95. }
  96. // FieldOk returns the field from a nested struct. The boolean returns whether
  97. // the field was found (true) or not (false).
  98. func (f *Field) FieldOk(name string) (*Field, bool) {
  99. value := &f.value
  100. // value must be settable so we need to make sure it holds the address of the
  101. // variable and not a copy, so we can pass the pointer to strctVal instead of a
  102. // copy (which is not assigned to any variable, hence not settable).
  103. // see "https://blog.golang.org/laws-of-reflection#TOC_8."
  104. if f.value.Kind() != reflect.Ptr {
  105. a := f.value.Addr()
  106. value = &a
  107. }
  108. v := strctVal(value.Interface())
  109. t := v.Type()
  110. field, ok := t.FieldByName(name)
  111. if !ok {
  112. return nil, false
  113. }
  114. return &Field{
  115. field: field,
  116. value: v.FieldByName(name),
  117. }, true
  118. }