All notable changes to this project are documented in this file.
The format is based on Keep a Changelog, and this project adheres to Semantic Versioning.
- Major: backwards incompatible package updates
- Minor: feature additions
- Patch: bug fixes, backward compatible model and function changes, etc.
- v2.1.4 - 2026-05-14 (Go 1.21+)
- v2.1.3 - 2026-05-13 (Go 1.21+)
- v2.1.2 - 2026-05-13 (Go 1.21+)
- v2.1.1 - 2026-05-04 (Go 1.21+)
- v2.1.0 - 2026-04-20 (Go 1.21+)
- v2.0.5 - 2025-11-12 (Go 1.24+)
- v2.0.4 - 2025-11-03 (Go 1.24+)
- v2.0.3 - 2024-02-22 (Go 1.21+)
- v2.0.2 - 2023-12-30 (Go 1.18+)
- v2.0.1 - 2023-12-28 (Go 1.18+)
- v2.0.0 - 2023-12-23 (Go 1.18+)
- v1.0.2 - 2020-06-25 (Go 1.14+)
- v1.0.1 - 2020-06-25 (Go 1.14+)
- v1.0.0 - 2020-05-02 (Go 1.14+)
Internal package refactoring, ToStruct/ToStructE removal, documentation corrections, flag-behavior fixes, and substantially expanded test and example coverage.
ToStruct[T]— public API removed. Usecast.To[T]instead; struct hydration is dispatched automatically whenTis a struct type.ToStructE[T]— public API removed. Usecast.ToE[T]instead. The implementation moved tointernal/castasToStructE.- README references to
cast.ToStruct[T]/cast.ToStructE[T]replaced withcast.To[T]/cast.ToE[T].
Implementation moved out of the public package surface:
to.goandto.type.goremain inpackage castand exposeTo,ToE, and the public type API.- All converter sources (
to.bool.go,to.int.go,to.float.go,to.complex.go,to.string.go,to.slice.go,to.map.go,to.chan.go,to.func.go,to.struct.go,to.time.go,to.duration.go,to.big.go,to.net.go,to.url.go,to.regexp.go,util.decode.go,util.reflect.go) moved tointernal/cast/. - All
*_test.gofiles moved tointernal/cast/excepttest.examples_test.go, which stays in main to validate the public API surface via godoc examples. - Non-generic public types (
Flag,Op, flag constants, error vars) are defined in the internal package; main package re-exports them via Go type aliases. Generic types (Func,Types,Tbase,Tslice,Tchan,Tmap) stay in main because Go 1.21 does not support generic type aliases. - Internal
opsstruct renamed toOpswith exported fields so the main package can construct it viainternal.ParseOps. makeChan/makeFuncrewritten to use reflection-based casting (CastToType) instead of recursively calling the publicToE, breaking the otherwise-circular import path between main and internal.ToChanandToFuncare non-generic in the internal package; main'sToEperforms the final type assertion (withreflect.Convertfallback) to produce the user's namedchan TorFunc[T].
- Added
FORMATrow to the README Options table (previously absent). - Added Type and Scope columns to the Options table; reordered rows to match the constant declaration order.
- Added a "Global flag propagation" subsection below the table with runnable examples showing
ABS,JSON,LENGTH,UNIQUE_VALUES, andFORMATpropagating into nested casts. - All flag constants in
internal/cast/to.type.gonow carry full multi-line doc comments stating their value type, scope, applicability, and propagation behavior.
Happy-path ExampleToE_* functions that never showed an error have been renamed to ExampleTo_* and switched to cast.To; the freed-up ExampleToE_* names now hold corresponding error examples. Every ExampleTo_* has a matching ExampleToE_* error example. Total example functions: 73.
33 new sub-tests cover previously-untested ✗ cells of the conversion table: scalar → map errors, scalar → struct errors, slice/map/struct → bool|complex errors, map → int/uint/float errors, struct → uint error, and the documented []byte/[]rune → map[K]V success path. New ABS coverage added for negative float64 sources and negative-float strings to uint targets.
24 new example functions covering previously-undocumented type categories: time.Time (string, int, float, FORMAT), time.Duration (string, int), net.IP (string, packed uint32), *url.URL, *regexp.Regexp, *big.Int (decimal, hex), *big.Float, bool, complex64/complex128, error and fmt.Stringer interface targets, DECODE (scalar and slice), []byte → string, JSON-string → map, nested chan []int and Func[chan int].
time.Time → *big.Int now uses val.UnixNano() (was val.Unix()). *big.Int → time.Time already used nanoseconds, so the round-trip is now lossless for times within int64 range. Three test cases in TestTimeToBigConversions were updated accordingly.
- Named-type table footnote ᵗ said
*big.Int → time.Timewas Unix seconds; corrected to nanoseconds.*big.Float → time.Timeremains documented as Unix seconds with fractional precision. - Supported Conversions table cell for
string → map[K]Vwas✗, but JSON-object/array strings auto-decode; corrected to~ⁿwith a new footnote. - Note ⁴ for
string → boolsaid onlystrconv.ParseBoolvariants are accepted; the integer-parse fallback path was undocumented and is now described ("-1"→ true,"0.1"→ false becausefloor(0.1) = 0, etc.). - Note ᵈ and the named-type example for
int*→time.Timeclaimed Unix seconds; corrected to nanoseconds. ThetoTimedocstring previously said "Unix seconds" for integer sources; fixed to "Unix nanoseconds".
FORMATconstant comment said "time/duration parsing"; onlytime.Timereadsops.FormatVal. Corrected.PRIVATEconstant comment said "include unexported struct fields in map output" — too narrow. Corrected to describe both directions (struct→map source-field reading and map/struct→struct target hydration).- README
ABSrow said "negative signed inputs";ABSalso applies to negativefloat32/float64sources and numeric strings that parse to negative floats. Description, example block, and IMPORTANT callout updated.
When FORMAT is not set, parseTimeString falls through to time.Parse("", str) after the 19-format loop. The empty string "" is a valid source that returns time.Time{} because time.Parse("", "") succeeds. Now documented in both the function godoc and the README footnote ᶠ.
Every converter type-asserts the DEFAULT value at the top, before inspecting the input. Passing a wrong type returns an error immediately even for inputs that would otherwise convert successfully. Now documented on the Op struct, the DEFAULT constant, and the README Options table.
IMPORTANTcallout updated to describe the actualstring → booltwo-step parse behavior and to mention float-source applicability forABS.- Named-type code example updated to use a meaningful Unix-nanosecond value (
int64(1_713_787_200_000_000_000)for 2024-04-22) instead of a value that only made sense as Unix seconds. - The struct-hydration example block under
#### Structsrewritten to usecast.To/cast.ToEafter the removal ofToStruct/ToStructE.
Code quality, documentation, and test improvements.
- Doc comments added to previously undocumented exported and internal symbols:
TmaptypeErrorSignedToUnsigned,ErrorInvalidOption,ErrorStrErrorCastingFunc,ErrorStrUnableToCast(clarifying the string vars are format strings, not error values)castToType— all 8 dispatch cases documented
- New godoc examples:
ExampleTo_map,ExampleTo_struct,ExampleToE_mapDuplicateKeyError,ExampleToE_structNested,ExampleToE_structStrict,ExampleToE_mapToPrivateStruct.
- Renamed the sentinel error variable
ErrortoErrorUnableToCast.Erroris retained as a deprecated alias with a// Deprecated:godoc annotation for backward compatibility. - Example function suffixes converted from
snake_casetocamelCase(e.g.ExampleToE_mapFromMap) so all examples appear in godoc. Suffixes containing underscores are silently dropped by godoc.
ToEdoc referenced non-existent typeOps(correct type isOp) and contained double word "the the" — corrected.ToStructEdoc omitted*structas a valid source type — corrected.toSlicedoc was circular and meaningless — rewritten.ops.Globaldoc omittedFORMATfrom the global flag list andDECODEfrom the local flag list — corrected.parseOpsdoc omittedFORMATandDECODEfrom its description of preserved values — corrected.opsstruct doc incorrectly stated all non-default flags are pre-parsed tobool;FORMATandDECODEare stored as strings — corrected.TestPointerDerefLoop"pointer-to-interface" sub-test usederrors.Newwhose concrete pointer type is opaque; replaced with a localptrReceiverErrortype that hasError()on*Tonly, making the pointer-receiver guard explicit and self-documenting.
Code quality, bug fixes, and internal refactoring.
fieldKey now resolves a struct field's source-map key with the following priority: cast tag → json tag (name portion only) → field name. A tag value of "-" causes the field to be skipped during both struct hydration and struct→map conversion. This applies uniformly to hydrateStruct, collectSourceFieldValues, collectStructFields, and collectExportedFields.
ToStructE / toStruct now support the PRIVATE flag. When set, unexported fields are included in both source collection and target hydration. Unexported fields are read via extractFieldValue; unexported target fields are set via unsafe.Pointer (the only mechanism available without CGo).
Four internal helpers that had grown beyond their origin files are now defined exclusively in util.reflect.go:
fieldKey— moved fromto.struct.goextractFieldValue— moved fromto.map.goisNamedScalarStructType— moved fromto.slice.goisScalarKind— moved fromto.slice.go
The pointer-unwrapping loop now also dereferences pointer-to-struct sources when the target type is a struct. This makes *myStruct → myStruct consistent with the existing *int → int behavior. Pointer-to-interface sources and struct pointers whose target is not a struct (e.g. *regexp.Regexp when casting to *regexp.Regexp, or *errorT when casting to error) are left as-is so that pointer-receiver interface implementations continue to work correctly.
- Multi-level nil pointer overwrites
nil(to.go): when unwrapping a pointer chain such as**Twhere the outer pointer is non-nil but the inner*Tis nil,changedwas lefttrue, causing the post-loopval = srcVal.Interface()assignment to overwrite theval = nilset during the nil check with a typed nil(*T)(nil). Fixed by resettingchanged = falsein the nil branch. - Dead
errvariable instrToFloat(to.float.go): the finalreturn TTo(val), erralways returned a nilerr— the variable is cleared before reaching that line. Changed toreturn TTo(val), nil.
Struct hydration, seven new named-type cast targets, pointer dereferencing, and reflection infrastructure improvements.
Any map, struct, or *struct can now be cast into a user-defined struct type via ToStruct[T] / ToStructE[T], or via the standard To[T] / ToE[T] entry points. Source map keys are matched case-sensitively to exported field names. Fields whose source value cannot be cast retain their zero value by default; the STRICT flag promotes mismatches and unknown keys to errors. Supported sources:
map[string]anyand any map whose keys are string-castable- struct or
*struct(exported field names become keys; anonymous/embedded fields are promoted)
Nested structs, slices of structs, and embedded (anonymous) struct fields — including those from unexported embedded types and nil embedded pointer fields — are all handled recursively.
Seven standard Go types are now first-class cast targets via To[T] / ToE[T]:
| Target | File | Sources |
|---|---|---|
time.Time |
to.time.go |
string (19 formats), time.Time, *time.Time, integer (Unix ns), float (Unix s) |
time.Duration |
to.duration.go |
time.Duration, string (time.ParseDuration), integer/float (nanoseconds) |
net.IP |
to.net.go |
net.IP, string, []byte (4 or 16 bytes), uint32 (packed IPv4) |
*url.URL |
to.url.go |
*url.URL, url.URL, string |
*regexp.Regexp |
to.regexp.go |
*regexp.Regexp, string |
*big.Int |
to.big.go |
*big.Int, big.Int, *big.Float, string (base auto-detect), integer types, float types |
*big.Float |
to.big.go |
*big.Float, big.Float, *big.Int, string, integer types, float types |
All converters support the DEFAULT op (return the supplied fallback on error) and a default: string-cast fallback path for unrecognized source types.
All new targets are also supported as struct field types during struct hydration.
A single namedConverters map[reflect.Type]func(any, ops)(any, error) table is the authoritative registry for all named-type converters. Both ToE and castToType consult it before the generic kind dispatch, eliminating previously duplicated switch blocks. The companion rawToValue helper ensures that DEFAULT values are propagated to callers on converter failure instead of being silently dropped.
castToType now handles reflect.Struct and reflect.Pointer kinds in addition to scalars, slices, funcs, and chans, enabling recursive hydration of arbitrary nested types during struct field casting.
- Nil
*Tanonymous (embedded) pointer fields are now allocated before recursion inhydrateStruct, so promoted fields are properly hydrated instead of being skipped. collectExportedFieldsnow recurses into unexported anonymous struct types (matchinghydrateStructsemantics), fixing a gap where exported fields within unexported embedded types were missed during struct→struct conversion.DEFAULTvalues supplied tocastToStructTypeare now correctly propagated to the caller on error instead of being discarded.toStructno longer allocates a zero-value struct fordefaultValwhen aDEFAULTop is provided.
Full test coverage added for all new functionality: to.struct_test.go, to.time_test.go, to.duration_test.go, to.net_test.go, to.url_test.go, to.regexp_test.go, to.big_test.go.
Map target implementations, extended channel targets, extended function targets, expanded type definitions, performance improvements, expanded test coverage.
toMapfully implemented; three source kinds are supported:- map → map: keys and values are individually cast to the target types;
duplicate key detection is opt-in via the new
DUPLICATE_KEY_ERRORflag. - *struct / struct → map: exported field names become keys; anonymous
(embedded) struct fields are promoted to the top level; nested structs
recurse into
map[K]anyormap[K]map[...]when the value type allows. Unexported fields are included whenPRIVATE=true. - slice / array → map: element indices become keys, keys and values are cast to the target value types.
- map → map: keys and values are individually cast to the target types;
duplicate key detection is opt-in via the new
- New
Opflags:DUPLICATE_KEY_ERROR(bool, defaultfalse) — error on duplicate key after casting (map→map only).PRIVATE(bool, defaultfalse) — include unexported struct fields (struct→map only).STRICT(bool, defaultfalse) — return an error instead of silently skipping unconvertible fields (struct→map only).
toChan now handles composite element types in addition to scalars:
chan []T— channel of sliceschan Func[T]— channel of closureschan chan T— channel of channels
toFunc now handles composite return types in addition to scalars:
Func[[]T]— closure returning a sliceFunc[chan T]— closure returning a channelFunc[chan []T]— closure returning a channel of slicesFunc[chan Func[T]]— closure returning a channel of closuresFunc[chan chan T]— closure returning a channel of channels
New internal package-level functions shared by toMap, toChan, and toFunc:
castToKind— cast any value to a scalarreflect.KindcastToType— cast any value to an arbitraryreflect.Type(handles interface, slice, func, chan, and scalar targets)castToSliceType— element-wise cast to a named or concrete slice type
- Added
~chan chan Tbaseto theTchanconstraint, enablingchan chan Tas a concrete target type. - Added
PRIVATEandSTRICTflag constants (see Map section above).
- Expand support for Go v1.21 to current.
- Uncommented and wired the
reflect.Mapcase totoMap. reflect.Arrayandreflect.Slicecases now both accept array sources (previously only slice sources were accepted for slice targets).- Replaced incorrect goroutine-based panic recovery with
defer/recover. - Removed an unnecessary intermediate
reflect.Value(from) that wrappedval; internal helpers now receivevaldirectly, eliminating a layer of reflection indirection and fixing type-display in error messages.
- Replaced per-type inline make+send blocks with a shared
makeChan[T]generic helper (cast, make, send, return).
- Replaced per-type inline logic with calls to
makeFunc[T]and the new array/chan reflection helpers.
error/fmt.Stringerinterface target documentation: the README incorrectly claimed that any source value could be cast toerrorby converting it to a string message. The actual behavior — and the behavior validated byto.interface_test.go— is that values are accepted only when they already implement the target interface, and are returned as-is. Documentation now accurately describes pass-through semantics.
to.map_test.go— 21 new tests covering map→map (includingDUPLICATE_KEY_ERROR), struct→map (includingPRIVATE,STRICT, nested struct recursion, embedded field promotion, pointer source), and slice/array→map.to.interface_test.go— 11 new tests forerror,std_error.Error, andfmt.Stringerinterface targets, documenting pass-through semantics.examples_test.go— 9 new runnable examples:To[[]int],ToE[[]int]withUNIQUE_VALUES,To[chan int],ToE[chan int]withLENGTH,To[Func[int]],ToE[map[string]int]from map/struct/slice, andToE[string]withJSON.
- Corrected function signatures:
To[T Types](v any, o ...Op) TandToE[T Types](v any, o ...Op) (T, error)(previously showed wronganyconstraint and omitted the variadicOpparameter). - Added Options section with a full flag reference table (all 8 flags, their types, defaults, applicable targets, and descriptions).
- Added examples for slice, map, channel, func, string with
JSON, int withABS, anderror/fmt.Stringerinterface targets. - Corrected the conversion matrix:
slice→mapandmap→mapnow showy; newstructsource row added. - Removed incorrect claim that "any source value can be cast to
error". - Fixed several prose typos (straightforward, loosely, incoming, maintained, measurable).
- []byte to string conversion bugfix
- Remove debug code
- Upgrade to go v1.24
- Cleanup non-constant format strings
- GitHub action definition for builds and tests
- Related bug fixes and cleanup
- Added test coverage
- Related bug fixes and cleanup
- Additional examples
- Improved slice support
- Various bugfixes
- Added tests
This is a full library rewrite for go v1.18+ to take advantage of generic functions and types.
syntax example:
intVal := cast.To[int]("8.31") // 8 (int)
intVal := cast.To[int]("Hi!") // 0 (int)
intVal, err := cast.ToE[int]("Hi!") // 0, unable to cast "Hi!" of type string to int (int, error)- All existing exported cast functions have been removed (
ToString(any) string,ToStringE(any) (string, error), etc.)
- All previous exported cast functions have replaced with a single generic function (and it's
errorcounterpart):To[T any](any) T ToE[T any](any) (T, error)
ToUint64SliceToUint64SliceE
ToInt64SliceToInt64SliceE
v1.0.0 is the production release of the previous development work.