Documentation
¶
Overview ¶
Package gostructor fills the fields of a Go struct from a mix of configuration sources (environment variables, files, secret stores), driven by two struct tags: cfg for routing/naming and gos for behavior. See the README for the full guide. This file holds the engine: the Configure entry point and the resolution loop that walks a cached structplan.Plan and asks each Source, in slice order, for a value.
Sources are tried in the order passed to WithSources; the first that reports found=true wins. There is no per-field priority tag and no global selector: the slice order decides priority.
Index ¶
- Constants
- Variables
- func Configure[T any](target *T, opts ...Option) (*T, error)
- func DecodeINI(raw []byte) (map[string]any, error)
- func DecodeJSON(raw []byte) (map[string]any, error)
- func DecodeKeyValue(raw []byte) (map[string]any, error)
- func Identity(base string) string
- func LookupKey(field FieldContext, sourceName string, data map[string]any) (any, bool)
- func PollWatch(ctx context.Context, interval time.Duration, ...) error
- func ScreamingSnake(base string) string
- func Watch[T any](ctx context.Context, target *T, onReload func(*T, error), opts ...Option) error
- type Attempt
- type ConvertError
- type Decoder
- type FieldContext
- func (f FieldContext) Base() string
- func (f FieldContext) Flag(name string) bool
- func (f FieldContext) IsSecret() bool
- func (f FieldContext) Meta(key string) (string, bool)
- func (f FieldContext) Optional() bool
- func (f FieldContext) Override(source string) (string, bool)
- func (f FieldContext) Separator() string
- func (f FieldContext) SourceKey(source string, naming func(base string) string) string
- func (f FieldContext) TagValue(tagName string) string
- type FieldError
- type FieldResolution
- type Hook
- type HookError
- type Masker
- type NotResolvedError
- type Option
- type Report
- type Source
- type SourceError
- type Watchable
Constants ¶
const ( SourceEnv = "env" SourceJSON = "json" SourceINI = "ini" SourceDefault = "default" )
Source names for the core module's built-in sources. These strings are what a cfg tag targets in a per-source override, e.g. `cfg:"port,env:DB_PORT"`.
const INIFileEnvVar = "GOSTRUCTOR_INI"
INIFileEnvVar names the environment variable INI reads its file path from, unless a path was given explicitly to INIFile.
const JSONFileEnvVar = "GOSTRUCTOR_JSON"
JSONFileEnvVar names the environment variable JSON reads its file path from, unless a path was given explicitly to JSONFile.
const KeyValueFileEnvVar = "GOSTRUCTOR_KEYVALUE"
KeyValueFileEnvVar names the environment variable KeyValue reads its file path from, unless a path was given explicitly to KeyValueFile.
const SourceKeyValue = "keyvalue"
SourceKeyValue is the key/value source's identity and its cfg per-source override key, e.g. `cfg:"host,keyvalue:DATABASE_HOST"`.
const SourceMap = "map"
SourceMap is the default identity of the in-memory Map source.
Variables ¶
var ErrFieldNotResolved = errors.New("no configured source produced a value")
ErrFieldNotResolved is the sentinel wrapped by *NotResolvedError: a field carried at least one recognized source tag, but no configured source produced a value for it. Match it with errors.Is:
if errors.Is(err, gostructor.ErrFieldNotResolved) { ... }
var ErrInvalidTarget = errors.New("gostructor: target must be a non-nil pointer to a struct")
ErrInvalidTarget is returned, wrapped, when Configure is called with a target that is not a non-nil pointer to a struct. Match it with errors.Is.
Functions ¶
func Configure ¶ added in v1.1.0
Configure fills target's fields in place and returns target for chaining. With no options it uses a minimal default source list: Env then Default. Add file and secret sources (JSON(), INI(), yaml.New(), vault.New(), ...) via WithSources; they are opt-in, so a bare cfg base name never triggers an unexpected file load.
func DecodeINI ¶ added in v1.1.0
DecodeINI parses an INI document into a nested map: global keys at the top level, each `[section]` a nested map. Values are strings.
func DecodeJSON ¶ added in v1.1.0
DecodeJSON parses JSON into a nested map, keeping numbers exact (json.Number) so large integers survive rather than being rounded through float64 — the same decoding the JSON source uses.
func DecodeKeyValue ¶ added in v1.1.0
DecodeKeyValue parses a flat `.env`/`.properties` file (see parseKeyValue) into a flat map of string values. It backs the KeyValue source and is reusable as a git/watch Decoder.
func Identity ¶ added in v1.1.0
Identity returns base unchanged. It is the naming strategy for file sources (JSON, YAML, TOML, HOCON, INI), whose keys are the base names as written; nested paths are given explicitly via a per-source override.
func LookupKey ¶ added in v1.1.0
LookupKey resolves field against an already-decoded, possibly nested map[string]any using the field's per-source override for sourceName (or its base name) as a dot-separated path ("server.host"). It returns found=false when the field has no key for this source or the path is absent/nil.
It is exported so remote map-backed sources in separate modules (git, Spring Cloud Config) resolve keys exactly like the built-in file sources.
func PollWatch ¶ added in v1.1.0
func PollWatch(ctx context.Context, interval time.Duration, fingerprint func(context.Context) (string, error), onChange func(), log *slog.Logger) error
PollWatch helps a Watchable source implement Watch by polling a cheap fingerprint (a commit SHA, a KV modify-index, a secret version) on an interval and calling onChange when it differs from the previous poll. It blocks until ctx is cancelled. A fingerprint error is logged (if log is non-nil) and retried on the next tick rather than ending the watch. A non-positive interval defaults to 30s. The first poll only establishes the baseline and does not fire onChange.
func ScreamingSnake ¶ added in v1.1.0
ScreamingSnake converts a base name to SCREAMING_SNAKE_CASE, the naming strategy for environment variables: "port" -> "PORT", "maxConns" -> "MAX_CONNS", "HTTPServer" -> "HTTP_SERVER". Hyphens, dots and spaces become underscores; camelCase and acronym boundaries get an underscore inserted.
func Watch ¶ added in v1.1.0
Watch fills target once, then keeps it live: whenever a Watchable source reports a change, it re-fills a fresh *T (same path as the initial fill) and delivers the result to onReload. It blocks until ctx is cancelled.
Reloads are transactional: a fresh copy is filled and validated before being published, so a failed reload leaves the last-known-good config serving and reports the error via onReload(nil, err) instead of crashing. onReload is called with the initial fill too, so callers can publish it (typically an atomic.Pointer swap) with the same code used for reloads.
A failed *initial* fill is fatal: Watch returns the error without calling onReload, like Configure. WithDebounce coalesces a burst of signals into one reload. With no Watchable source, Watch fills once and blocks until ctx ends.
Types ¶
type Attempt ¶ added in v1.1.0
type Attempt struct {
Source string // e.g. "env"
Status string // not-found | used | skipped | error
Detail string // the key looked up (env var, file key) or an error summary
}
Attempt records a single source's turn at resolving a field.
type ConvertError ¶ added in v1.1.0
type ConvertError struct {
Field string // struct field name being filled
Value any // the raw value a source produced
Target reflect.Type // the field's Go type
Cause error // the underlying conversion failure, if any
}
ConvertError reports a failure to convert a resolved raw value into a struct field's Go type: a fractional float into an int, an out-of-range number, a malformed duration string, and so on. It carries the offending value and target type, and unwraps to the underlying cause (a *strconv.NumError, a time.ParseDuration error, a TextUnmarshaler error) for a further errors.As.
func (*ConvertError) Error ¶ added in v1.1.0
func (e *ConvertError) Error() string
func (*ConvertError) FieldName ¶ added in v1.1.0
func (e *ConvertError) FieldName() string
FieldName reports the struct field this error concerns.
func (*ConvertError) Unwrap ¶ added in v1.1.0
func (e *ConvertError) Unwrap() error
type Decoder ¶ added in v1.1.0
A Decoder turns a configuration file's raw bytes into a nested map, the shape LookupKey addresses. It is the pluggable format layer for the remote, file-shaped sources (gostructor/git, gostructor/watch).
The core ships zero-dependency decoders — DecodeJSON, DecodeINI, DecodeKeyValue. The yaml/toml/hocon modules expose their own, so a format's decoder pulls in only that format's dependency.
type FieldContext ¶ added in v1.1.0
type FieldContext struct {
reflect.StructField
// contains filtered or unexported fields
}
FieldContext describes the struct field being resolved, exposing its parsed cfg (base name and per-source overrides) and gos (defaults, flags) metadata so a Source never has to parse struct tags itself.
func (FieldContext) Base ¶ added in v1.1.0
func (f FieldContext) Base() string
Base returns the field's base name (the first cfg element), from which each source derives its key when there is no explicit override.
func (FieldContext) Flag ¶ added in v1.1.0
func (f FieldContext) Flag(name string) bool
Flag reports whether a bare gos flag is present, as in `gos:"secret"` -> Flag("secret") == true.
func (FieldContext) IsSecret ¶ added in v1.1.0
func (f FieldContext) IsSecret() bool
IsSecret reports whether the field carries the gos secret flag; its value is masked everywhere it would otherwise print (report, trace, ConvertError).
func (FieldContext) Meta ¶ added in v1.1.0
func (f FieldContext) Meta(key string) (string, bool)
Meta returns a gos meta value, as in `gos:"default:8080"` -> Meta("default") == ("8080", true).
func (FieldContext) Optional ¶ added in v1.1.0
func (f FieldContext) Optional() bool
Optional reports whether the field carries the gos optional flag; an optional field left unresolved by every source is not an error.
func (FieldContext) Override ¶ added in v1.1.0
func (f FieldContext) Override(source string) (string, bool)
Override returns the explicit key a cfg tag set for source, as in `cfg:"port,env:SERVER_PORT"` -> Override("env") == ("SERVER_PORT", true).
func (FieldContext) Separator ¶ added in v1.1.0
func (f FieldContext) Separator() string
Separator returns the string used to split a flat value into slice elements: the gos sep meta if set, otherwise a comma.
func (FieldContext) SourceKey ¶ added in v1.1.0
func (f FieldContext) SourceKey(source string, naming func(base string) string) string
SourceKey returns the key source should look up for this field: the explicit per-source override if present, otherwise naming(Base()). It returns "" when there is no override and no base name, signalling the source does not apply.
func (FieldContext) TagValue ¶ added in v1.1.0
func (f FieldContext) TagValue(tagName string) string
TagValue is a convenience for field.Tag.Get(tagName), for the rare source that still wants a raw struct tag value.
type FieldError ¶ added in v1.1.0
FieldError is implemented by every Configure error scoped to one struct field: NotResolvedError, SourceError, ConvertError, and HookError. It lets a caller recover which field failed without switching on the concrete type:
var fe gostructor.FieldError
if errors.As(err, &fe) { ... fe.FieldName() ... }
type FieldResolution ¶ added in v1.1.0
type FieldResolution struct {
Field string // struct field name
Type string // Go type, e.g. "int", "time.Duration"
Attempts []Attempt // every source considered, in the order tried
Winner string // source name that produced the value, or "" if none
Raw any // value the winning source returned (masked if secret)
Value any // converted, field-typed value (masked if secret)
Outcome string // resolved | default | unresolved | error | skipped
IsSecret bool // field carries gos:"secret"
}
FieldResolution records the resolution of a single struct field: every source considered, the winner, and the raw and converted values.
type Hook ¶ added in v1.1.0
type Hook func(field FieldContext, value any) (any, error)
Hook runs after a value has been resolved for a field but before it is set on the struct, letting you validate or transform it. Returning an error aborts Configure with that error.
type HookError ¶ added in v1.1.0
type HookError struct {
Field string // struct field name the hook ran on
Cause error // the hook's error, or a type-mismatch description
}
HookError reports that a WithHook callback rejected or failed to transform a field's value. A hook that returns a non-nil error produces a HookError wrapping it; a hook that returns a value of the wrong type produces a HookError whose Cause explains the type mismatch. It unwraps to that cause.
type Masker ¶ added in v1.1.0
type Masker func(field FieldContext, value any) string
Masker renders a sensitive field's value for display. It is called for any field carrying the gos secret flag before its value reaches a log, the resolution report, or an error message. The default fully redacts.
type NotResolvedError ¶ added in v1.1.0
type NotResolvedError struct {
Field string // struct field name
Sources []string // the source names tried, in order
}
NotResolvedError reports that a configured field produced no value from any source. Sources lists the source names tried, in order, so the message can say precisely what was looked at (e.g. tried env, json). It wraps ErrFieldNotResolved.
func (*NotResolvedError) Error ¶ added in v1.1.0
func (e *NotResolvedError) Error() string
func (*NotResolvedError) FieldName ¶ added in v1.1.0
func (e *NotResolvedError) FieldName() string
FieldName reports the struct field this error concerns.
func (*NotResolvedError) Unwrap ¶ added in v1.1.0
func (e *NotResolvedError) Unwrap() error
type Option ¶ added in v1.1.0
type Option func(*config)
Option configures a single Configure call.
func WithDebounce ¶ added in v1.1.0
WithDebounce sets how long Watch waits for a source's change signals to go quiet before running one reload, collapsing a burst (an editor's several writes for one save, a config server's batch of key events) into a single re-fill. Zero disables debouncing (every signal reloads immediately). It has no effect on a plain Configure call.
func WithHook ¶ added in v1.1.0
WithHook registers a hook run after each field is resolved, in the order added. Use it for validation (return an error to reject a value) or transformation (return a different value).
func WithLogger ¶ added in v1.1.0
WithLogger sets the logger Configure uses for diagnostic output. The default is a no-op logger; pass slog.Default() (or your own) to see what gostructor is doing.
func WithMasker ¶ added in v1.1.0
WithMasker overrides how secret fields (gos:"secret") are rendered for display. The default fully redacts ("••••••"); pass your own to, say, reveal the last four characters. The masker is only ever called for fields carrying the gos secret flag.
func WithSources ¶ added in v1.1.0
WithSources replaces the default source list with an explicit, ordered one. Sources are tried in the order given; the first one that reports found=true for a field wins. This slice order is how priority is expressed: put the source that should win first. Use this to bring in external sources such as yaml.New() or vault.New(), since the core module only ships Env, JSON, INI, and Default.
func WithTrace ¶ added in v1.1.0
func WithTrace() Option
WithTrace makes Configure log the full resolution report at debug level through the configured logger (see WithLogger) once resolution completes. It has no effect without a logger. To capture the report programmatically instead, use ConfigureWithReport.
func WithValidate ¶ added in v1.1.0
WithValidate registers a whole-struct validation run during Watch after a reload has filled a fresh copy but before it is published. Returning an error rejects that reload: the previously good config keeps serving and the error is delivered to onReload rather than swapping in a broken value. It complements per-field WithHook (which runs during every fill) with a check that can see the whole struct at once. It has no effect on a plain Configure call; validate there is the caller's own concern.
type Report ¶ added in v1.1.0
type Report struct {
// Type is the configured struct's Go type, e.g. "main.Config".
Type string
// Fields holds one FieldResolution per struct field walked, in struct
// order (nested fields flattened, matching resolution order).
Fields []FieldResolution
}
Report is a per-field account of how Configure resolved a struct: which sources it tried for each field, in what order, which won, and what value came out. Obtain one from ConfigureWithReport; the plain Configure builds no report, so it is free when unused.
Report is the machine view. String() renders a focused summary of the actionable data: the primary source, the defaults, and an Overrides & Secrets section. Secret fields (gos:"secret") are masked throughout.
func ConfigureWithReport ¶ added in v1.1.0
ConfigureWithReport is Configure plus a resolution trace: for every field it records which sources were tried, in what order, which won, and the raw and converted values (secrets masked). Report is the machine view; its String() renders a human summary. On error the report is returned as far as resolution got.
func (*Report) PrimarySource ¶ added in v1.1.0
PrimarySource reports the source that resolved the most non-secret fields, i.e. the environment's main configuration origin (typically a YAML/JSON/TOML file). The Default source is never the primary. It returns "" when no non-default source won a non-secret field.
func (*Report) Provenance ¶ added in v1.1.0
Provenance projects the report down to the "field -> winning source name" map: the dependency view of how this environment assembled the config. Fields that resolved from no source (unresolved or unconfigured) are omitted.
func (*Report) String ¶ added in v1.1.0
String renders a focused resolution trace: a one-line summary, a one-liner for the primary source and for defaults, then an Overrides & Secrets section listing only the fields that were resolved by a non-primary, non-default source (an override) or that are secret. Fields resolved straight from the primary source or from a plain default are summarized by count, not listed.
Configuring main.Config: 5 fields [Primary Source] json (loaded 3 fields) [Defaults] applied for 1 field Overrides & Secrets: Port int ⇐ env (override; json had it too) Password string ⇐ vault •••••••• (secret)
type Source ¶ added in v1.1.0
type Source interface {
// Name is the source's short identity, e.g. "env". It doubles as the
// per-source override key in a cfg tag.
Name() string
// Resolve returns the raw value for field, or found=false if this
// source has nothing to contribute for it.
Resolve(field FieldContext) (value any, found bool, err error)
}
Source resolves one struct field's value from a single configuration origin: an environment variable, a parsed file, a secret store, and so on.
Resolve returns found=false when nothing in this source applies to the field (for example, the field has no key for this source), so the engine falls through to the next source instead of treating it as an error.
Name is the source's short identity ("env", "json", "vault", ...), and the key used to target it from a cfg per-source override such as `cfg:"port,env:SERVER_PORT"`.
Sources outside the core module (gostructor/yaml, gostructor/toml, gostructor/hocon, gostructor/vault, or your own) implement this interface to plug into Configure via WithSources.
func Default ¶ added in v1.1.0
func Default() Source
Default resolves fields from the literal value on the gos default meta, `gos:"default:8080"`. It has no external dependency and always applies when the meta is present, so it's typically placed last in a source list as the fallback. For a slice/array field the value is split on the field's separator (gos sep, default comma).
func Env ¶ added in v1.1.0
func Env() Source
Env resolves fields from environment variables. The variable name is the field's base name in SCREAMING_SNAKE_CASE (`cfg:"port"` -> PORT), unless the cfg tag overrides it (`cfg:"port,env:DB_PORT_LEGACY"` -> DB_PORT_LEGACY).
func INI ¶ added in v1.1.0
func INI() Source
INI resolves fields from the INI file named by the GOSTRUCTOR_INI environment variable. The key is the field's base name in the global, section-less part of the file (`cfg:"port"`); a value inside a section is addressed by overriding with "section#key" (`cfg:"port,ini:server#port"`).
func INIFile ¶ added in v1.1.0
INIFile is like INI but reads from path instead of the GOSTRUCTOR_INI environment variable.
func JSON ¶ added in v1.1.0
func JSON() Source
JSON resolves fields from the JSON file named by the GOSTRUCTOR_JSON environment variable. The key is the field's base name (`cfg:"host"` -> the top-level "host" key); a nested value is addressed by overriding the key with a dotted path (`cfg:"host,json:server.host"` -> "host" inside "server"). A bare object key like `cfg:"server"` addresses the whole nested object, for map[string]T destination fields.
func JSONFile ¶ added in v1.1.0
JSONFile is like JSON but reads from path instead of the GOSTRUCTOR_JSON environment variable.
func KeyValue ¶ added in v1.1.0
func KeyValue() Source
KeyValue resolves fields from a flat key/value file (the `.env`/`.properties` shape: `KEY=VALUE` lines, `#`/`;` comments, optional `export`, quoted values) named by the GOSTRUCTOR_KEYVALUE environment variable. A field's key is its base name as written (`cfg:"host"` -> the `host` key); pin a different key with a per-source override (`cfg:"host,keyvalue:DB_HOST"`). Values are strings; a slice/array field's value is split on the field separator.
func KeyValueFile ¶ added in v1.1.0
KeyValueFile is like KeyValue but reads from path instead of the GOSTRUCTOR_KEYVALUE environment variable.
func Map ¶ added in v1.1.0
Map returns a Source backed by an in-memory map, resolving fields with the same nested-key addressing as the JSON source (see LookupKey). It is handy as a highest-priority override in tests and programmatic setups — put it first in WithSources. name is the source identity and cfg override key; empty defaults to SourceMap.
type SourceError ¶ added in v1.1.0
type SourceError struct {
Field string // struct field name being resolved
Source string // the failing source's name, e.g. "json"
Cause error // the error the Source returned
}
SourceError reports that a configured Source failed while resolving a field: a JSON file that doesn't exist or parse, an unreachable Vault server, and so on. Source names the failing source (e.g. "json") so you can tell which of several sources went wrong. It unwraps to the error the Source returned.
func (*SourceError) Error ¶ added in v1.1.0
func (e *SourceError) Error() string
func (*SourceError) FieldName ¶ added in v1.1.0
func (e *SourceError) FieldName() string
FieldName reports the struct field this error concerns.
func (*SourceError) Unwrap ¶ added in v1.1.0
func (e *SourceError) Unwrap() error
type Watchable ¶ added in v1.1.0
Watchable is an optional interface a Source may implement to signal that its backing data can change while the program runs. Watch (see watch.go) subscribes to every configured source that implements it and re-fills the target struct whenever any of them reports a change.
Watch (the method) blocks until ctx is cancelled, calling onChange each time the underlying data changes. It must honour ctx — returning ctx.Err() once cancelled — and return any fatal error otherwise. onChange may be invoked from any goroutine and must be safe to call repeatedly; the Watch driver coalesces bursts through WithDebounce, so a source need not debounce itself.
A source that caches a snapshot for Resolve should refresh that snapshot *before* calling onChange, so the re-fill triggered by onChange reads the new data rather than the old.
Source Files
¶
Directories
¶
| Path | Synopsis |
|---|---|
|
examples
|
|
|
basic
command
Command basic shows the minimum gostructor setup: env vars (named from each field via the cfg tag) with gos default fallbacks, using only the core module.
|
Command basic shows the minimum gostructor setup: env vars (named from each field via the cfg tag) with gos default fallbacks, using only the core module. |
|
errors
command
Command errors tours gostructor's typed error taxonomy: it triggers each failure mode and classifies it with errors.Is / errors.As, so a caller can tell what went wrong and whose fault it is.
|
Command errors tours gostructor's typed error taxonomy: it triggers each failure mode and classifies it with errors.Is / errors.As, so a caller can tell what went wrong and whose fault it is. |
|
filesources
command
Command filesources shows the two core file sources, JSON and INI, used together on one struct with env and a gos default in the same priority chain.
|
Command filesources shows the two core file sources, JSON and INI, used together on one struct with env and a gos default in the same priority chain. |
|
hooks
command
Command hooks shows WithHook for two jobs: transforming a resolved value (normalise a string) and validating one (reject an out-of-range port), both operating on the already-converted, field-typed value.
|
Command hooks shows WithHook for two jobs: transforming a resolved value (normalise a string) and validating one (reject an out-of-range port), both operating on the already-converted, field-typed value. |
|
observability
command
Command observability shows gostructor's focused resolution trace: a summary line, the primary source, the defaults count, and an Overrides & Secrets section listing only the fields that were overridden away from the primary config or that are secret (masked).
|
Command observability shows gostructor's focused resolution trace: a summary line, the primary source, the defaults count, and an Overrides & Secrets section listing only the fields that were overridden away from the primary config or that are secret (masked). |
|
priority
command
Command priority shows how gostructor expresses priority: the SAME struct resolves DIFFERENTLY purely from the ORDER of sources passed to WithSources.
|
Command priority shows how gostructor expresses priority: the SAME struct resolves DIFFERENTLY purely from the ORDER of sources passed to WithSources. |
|
types
command
Command types shows the range of field types gostructor fills from a single structured source (a JSON file here): durations, slices and arrays, TextUnmarshaler types (time.Time, net.IP), named scalar types, pointers, maps, and slices/maps of structs, all with strict, lossless conversion.
|
Command types shows the range of field types gostructor fills from a single structured source (a JSON file here): durations, slices and arrays, TextUnmarshaler types (time.Time, net.IP), named scalar types, pointers, maps, and slices/maps of structs, all with strict, lossless conversion. |
|
webservice
command
Command webservice is a production-style microservice configuration assembled from three layers:
|
Command webservice is a production-style microservice configuration assembled from three layers: |
|
internal
|
|
|
convert
Package convert turns the loosely-typed values a config source parses (strings, float64s from JSON, []interface{} from YAML) into the concrete Go types of the struct fields gostructor is filling.
|
Package convert turns the loosely-typed values a config source parses (strings, float64s from JSON, []interface{} from YAML) into the concrete Go types of the struct fields gostructor is filling. |
|
format/ini
Package ini is a small, hand-written INI parser covering the practical subset gostructor needs: `[section]` headers, `key = value` or `key: value` pairs, `;`/`#` line comments, and quoted values.
|
Package ini is a small, hand-written INI parser covering the practical subset gostructor needs: `[section]` headers, `key = value` or `key: value` pairs, `;`/`#` line comments, and quoted values. |
|
structplan
Package structplan builds and caches, per reflect.Type, the flattened list of settable fields on a struct, each with its config metadata already parsed from the two struct tags gostructor understands:
|
Package structplan builds and caches, per reflect.Type, the flattened list of settable fields on a struct, each with its config metadata already parsed from the two struct tags gostructor understands: |
|
watch
module
|