Awesome
Package set
is a performant reflect wrapper supporting loose type conversion, struct mapping and population, and slice building.
The godoc
documentation has detailed information and many examples but following is the high-level view.
Type Coercion
Type coercion allows assignment from loosey-goosey sources -- for example incoming string data -- to strongly typed Go types.
var t T // T is a target data type, t is a variable of that type.
var s S // S is a source data type, s is a variable of that type.
set.V(&t).To(s) // Sets s into t with a "best effort" approach.
Struct Population with Getter
set.Value
has two methods, Fill
and FillByTag
, that use the set.Getter
interface as the provider for data to populate a struct and its hierarchy.
For convenience:
set.GetterFunc
allows plain functions to be used as aset.Getter
similar tohttp.HandlerFunc
.set.MapGetter
allows eithermap[string]T
ormap[interface{}]T
to be used as aset.Getter
.
Struct Mapping
set.Mapper
is a powerful and highly configurable struct mapping facility.
A mapper will traverse a struct hiearchy and create a 1:1
mapping of friendly names
to traversal information
. The friendly names can then be used to target associated fields within a struct value and its hierarchy.
Example usages of a mapper are to map CSV column headings to struct fields, database column names to struct fields, or creating a generic struct copier to marshal structs across different domains or boundaries in your application architecture.
set.Mapper
contains several configuration fields that can be used to fully customize the generated friendly names
:
- Choose how nested names are combined:
VendorName
,Vendor_Name
,Vendor.Name
,vendor_name
, etc. - Specify multiple tags in order of preference:
db
tag values can have higher precedence thanjson
tags - Elevate types into a higher namespace: see the Mapper example(s)
- Specify types that are ignored and don't get mapped.
- Specify types that are treated as scalars: useful for sql.Null* types or similar
BoundMapping and PreparedMapping
Once a set.Mapper
(described above) is created it can return BoundMapping
or PreparedMapping
types that are bound to Go structs. In turn BoundMapping
and PreparedMapping
provide performant access to the bound data via the friendly names generated by the mapper.
A BoundMapping
provides an adhoc access to struct fields; each method takes the mapped name of the field to access. An example use case for BoundMapping
is populating data when some of the data may be missing and you may not set data for every possible mapped field.
A PreparedMapping
is similar to a prepared SQL statement and the access plan must be set with a call to its Plan
method. An example use case for PreparedMapping
is populating CSV data or database rows where every row is guaranteed to access the same fields in the same order.
Performance Notes
Package reflect
is always slower than code not using reflect
. A considerable effort has been spent designing and implementing this package to reduce reflect overhead.
reflect
data is generally only gathered once (via reflect.TypeOf, reflect.ValueOf) when first encountering a type. This data is cached and retrieved from cache on further encounters with repeated types.- Value assigning is generally attempted first with type switches and then falls back to
reflect
. This strategy is heavily used during type coercion. - Appropriate types in this package have a
Rebind
method.Rebind
will swap a "bound" Go type with a new incoming instance without making additional expensive calls intoreflect
. The outgoing and incoming types must be compatible but this is the expected usage in tight loops building slices of data.
Additionally this package attempts to be low allocation so as not to overwhelm the garbage collector.
- Some of the methods on BoundMapping and PreparedMapping allow a dest slice to be pre-allocated.
- BoundMapping, PreparedMapping, and Value are created and returned as structs instead of pointers.
API Consistency and Breaking Changes
I am making a very concerted effort to break the API as little as possible while adding features or fixing bugs. However this software is currently in a pre-1.0.0 version and breaking changes are allowed under standard semver. As the API approaches a stable 1.0.0 release I will list any such breaking changes here and they will always be signaled by a bump in minor version.
-
0.4.0 ⭢ 0.5.0
-
README-0.4.0-to-0.5.0.md outlines many of the package changes, reasoning, and benchmarks
-
Remove erroneous documentation for
Value.To
method.
The documentation indicated that when Dst and Src are both pointers with same level of indirection that direct assignment was performed. This is not true. The Value type uses the values at the end of pointers and pointer chains and therefore does not perform direct assignment of pointer values.
-
-
0.3.0 ⭢ 0.4.0
set.Mapper has new field TaggedFieldsOnly.TaggedFieldsOnly=false
means no change in behavior.TaggedFieldsOnly=true
means set.Mapper only maps exported fields with struct tags. -
0.2.3 ⭢ 0.3.0
set.BoundMapping.Assignables has a second argument allowing you to pre-allocate the slice that is returned; you can also set it tonil
to keep current behavior.