Documentation
¶
Overview ¶
Utilities missing from the "reflect" package: easier struct traversal, deep dereferencing, various boolean tests such as generic `IsNil`, and some more. Small and dependency-free.
Naming Conventions ¶
• Functions that take a `reflect.Value` have "Rval" in the name.
• Functions that take a `reflect.Type` have "Rtype" in the name.
API Considerations ¶
In general, utils for struct traversal can be implemented as function that take closures, or as stateful iterator objects. Both approaches were tested and demonstrated similar performance characteristics. The iterator-based approach can be more convenient to use because it doesn't interrupt the control flow of the caller code. However, the closure-based approach is much simpler to implement and get right. It's also much simpler to wrap, making it easier for users of this package to implement their own iterator functions in terms of the existing ones.
Index ¶
- Variables
- func IsColl(val interface{}) bool
- func IsEmptyColl(val interface{}) bool
- func IsNil(val interface{}) bool
- func IsNilable(val interface{}) bool
- func IsRkindColl(kind reflect.Kind) bool
- func IsRkindNilable(kind reflect.Kind) bool
- func IsRvalEmptyColl(rval reflect.Value) bool
- func IsRvalNil(rval reflect.Value) bool
- func IsRvalZero(rval reflect.Value) bool
- func IsSfieldExported(sfield reflect.StructField) bool
- func IsZero(val interface{}) bool
- func KindOf(val interface{}) reflect.Kind
- func RtypeDeref(rtype reflect.Type) reflect.Type
- func RvalDeref(rval reflect.Value) reflect.Value
- func RvalDerefAlloc(rval reflect.Value) reflect.Value
- func RvalFieldByPathAlloc(rval reflect.Value, path []int) reflect.Value
- func TagIdent(tag string) string
- func TraverseStruct(val interface{}, fun func(reflect.Value, reflect.StructField, []int) error) error
- func TraverseStructRtype(rtype reflect.Type, fun func(reflect.StructField, []int) error) error
- func TraverseStructRval(rval reflect.Value, fun func(reflect.Value, reflect.StructField, []int) error) error
- func TraverseStructType(val interface{}, fun func(reflect.StructField, []int) error) error
- type Error
Constants ¶
This section is empty.
Variables ¶
var ( ErrMissingFunc = Error(`refut: missing callback function`) ErrInvalidType = Error(`refut: received invalid type`) ErrInvalidValue = Error(`refut: received invalid value`) )
Functions ¶
func IsColl ¶
func IsColl(val interface{}) bool
Returns true if the kind of the provided value is a collection. See `IsRkindColl` for further details. Note that this follows `reflect.Value.Len` rather than the built-in `len` in that pointers to arrays are not considered to be collections.
func IsEmptyColl ¶
func IsEmptyColl(val interface{}) bool
Returns true if the input belongs to one of the kinds "reflect" considers collections (see `IsRkindColl`), and has the length of zero. Nils are included.
func IsNil ¶
func IsNil(val interface{}) bool
Similar to `X == nil`, but returns true if the input is a non-nil `interface{}` whose underlying concrete type is nilable (pointer, slice, map, channel, func) and its underlying concrete val is nil.
func IsNilable ¶
func IsNilable(val interface{}) bool
Returns true if the kind of the provided value is nilable. See `IsRkindNilable` for further details. As a special case, this returns true for a nil input, even though it carries no type information.
func IsRkindColl ¶
Returns true for the kinds "reflect" considers collections: array, chan, map, slice, or string. These are the kinds for which it's safe to call `reflect.Value.Len` without panicking.
func IsRkindNilable ¶
Returns true for the kinds "reflect" considers nilable: chan, func, interface, map, pointer, or slice. These are the kinds for which it's safe to call `reflect.Value.IsNil` without panicking.
func IsRvalEmptyColl ¶
Variant of `IsEmpty` that takes a `reflect.Value` as input. See `IsEmpty` for the documentation.
func IsRvalNil ¶
Variant of `IsNil` that takes a `reflect.Value` as input. See `IsNil` for the documentation.
func IsRvalZero ¶ added in v0.1.3
Variant of `reflect.Value.IsZero` that returns false for invalid values instead of panicking.
func IsSfieldExported ¶
func IsSfieldExported(sfield reflect.StructField) bool
func IsZero ¶ added in v0.1.3
func IsZero(val interface{}) bool
Returns true if the input is a zero value of its type. As a special case, returns true if the input itself is nil (carries no type information).
func RtypeDeref ¶
Takes a `reflect.Type` and dereferences as many times as needed until it's no longer a pointer type. A nil type is ok and returns nil.
Note: if the type is defined recursively as a pointer to itself, this will loop forever.
func RvalDeref ¶
Takes a `reflect.Value` and dereferences as many times as needed until it's no longer a pointer. Panics if any pointer in the sequence is nil.
func RvalDerefAlloc ¶
Takes a `reflect.Value` and dereferences as many times as needed until it's no longer a pointer, while allocating intermediary values as necessary. If the input value is a pointer, it must be settable or non-nil, otherwise this causes a panic.
Example:
var val ***string
rval := refut.RvalDerefAlloc(reflect.ValueOf(&val))
rval.SetString("hello world")
fmt.Println(***val) // "hello world"
func RvalFieldByPathAlloc ¶
Variant of `reflect.Value.FieldByIndex` that allocates intermediary values for fields which are struct pointers. For example:
type Inner struct { Value string }
type Outer struct { *Inner }
var outer Outer
rval := refut.RvalFieldByPathAlloc(reflect.ValueOf(&outer), []int{0, 0})
rval.SetString("hello world")
fmt.Println(outer.Value) // "hello world"
Unlike `reflect.Value.FieldByIndex`, this function also allows the input value to be a non-nil struct pointer of any depth, as seen in the example above.
func TagIdent ¶
Takes a struct field tag and returns the identifier part contained in it, as long as the tag follows the convention established by `json:""` tags:
json:"ident" json:"ident,<extra>" json:"-" json:"-,<extra>"
Ident "-" is converted to "".
Usage:
ident := TagIdent(sfield.Tag.Get("json"))
ident := TagIdent(sfield.Tag.Get("db"))
func TraverseStruct ¶
func TraverseStruct(val interface{}, fun func(reflect.Value, reflect.StructField, []int) error) error
Takes a struct value and traverses its fields, calling the provided function for each field. Skips non-exported (private) fields. Traverses the fields of embedded structs as if they were part of the enclosing struct.
The callback receives arguments for a specific struct field:
• `reflect.Value`: field value.
• `reflect.StructField`: field description.
• `[]int`: path to the field, suitable for `reflect.Value.FieldByIndex` or `RvalFieldByPathAlloc` on the root value. See `TraverseStructType` for notes about the path.
WARNING: the path slice is allocated once and mutated between iterations. To store the path for later use, you MUST copy the slice.
The input may be a struct pointer, which is automatically dereferenced. Nil struct pointers at the root level or as embedded fields are okay and won't be traversed.
If the input is not a struct, or if the callback is nil, this function panics. Returned errors are always from the callback.
func TraverseStructRtype ¶
Variant of `TraverseStructType` that takes a `reflect.Type` as the input. See `TraverseStructType` for the documentation.
If the input is not a struct type, or if the callback is nil, this function panics. Returned errors are always from the callback.
func TraverseStructRval ¶
func TraverseStructRval(rval reflect.Value, fun func(reflect.Value, reflect.StructField, []int) error) error
Variant of `TraverseStruct` that takes a `reflect.Value` as the input. See `TraverseStruct` for the documentation.
If the input is not a struct, or if the callback is nil, this function panics. Returned errors are always from the callback.
func TraverseStructType ¶
func TraverseStructType(val interface{}, fun func(reflect.StructField, []int) error) error
Takes a struct value and traverses the fields of its type, calling the provided function for each field. Skips non-exported (private) fields. Traverses the fields of embedded structs as if they were part of the enclosing struct.
This function is provided for convenience; it ignores the actual value of its input. The input may be a struct or a struct pointer. Nil pointers are okay.
The callback receives arguments for a specific struct field:
• `reflect.StructField`: field description.
• `[]int`: path to the field.
The reason the path is a slice of ints, rather than one int, is because addressing a field of an embedded struct requires more than one index. The path is suitable for `reflect.Type.FieldByIndex` on the root type or `RvalFieldByPathAlloc` on a value of that type.
WARNING: the path slice is allocated once and mutated between iterations. To store the path for later use, you MUST copy the slice.
If the input is not a struct type, or if the callback is nil, this function panics. Returned errors are always from the callback.