Week 13 - Reflection: reflect, Performance, and Discipline¶
13.1 Conceptual Core¶
- The
reflectpackage exposes the runtime type system: every Go value has areflect.Type(its static type) and areflect.Value(a wrapper holding the value plus its type). Together they let you inspect and manipulate values whose concrete type is known only at runtime. - The two reflection use cases that matter:
- Generic serialization / deserialization (encoding/json, encoding/gob, gorm, sqlx)-when the input is
any. - Schema-driven adapters-config loaders, ORM tag parsers, validators.
- Reflection is slow. Roughly 5–50× the cost of direct field access. The standard libraries that use it (
encoding/json) compensate by cachingreflect.Typelookups and method tables per type.
13.2 Mechanical Detail¶
reflect.Typeis comparable (==) by identity-tworeflect.Typevalues are equal iff they describe the same Go type. This makesmap[reflect.Type]Cachea load-bearing pattern.reflect.Value.Kind()returns the underlying kind (Struct,Ptr,Slice, etc.).reflect.Value.Type()returns the named type. The two differ for named types:type MyInt inthas KindInt, TypeMyInt.- Field iteration:
t.NumField(),t.Field(i)returns aStructFieldwithName,Type,Tag,Index,Anonymous,PkgPath.Tag.Get("json")is the canonical tag-parsing path. - Method invocation:
v.Method(i).Call([]reflect.Value{...}). Allocates the slice and the result. unsafe.Pointershortcut: for performance-critical reflection, take the field address viaunsafe.Pointer(v.Field(i).UnsafeAddr())and read it as the typed value. This is whatmapstructureand high-performance JSON libraries do internally. Read the safety contract carefully-it's narrow.- Caching pattern:
13.3 Lab-"A Reflective Validator"¶
Build a struct validator that processes validate:"..." tags:
- Must support: required, min=N, max=N, email, regexp=<re>.
- Must cache per-type field metadata (one reflect.Type walk per type ever).
- Must produce structured errors (path, rule, value).
- Must beat a naive non-cached implementation by 10× in benchmarks.
Compare against go-playground/validator for both ergonomics and performance.
13.4 Idiomatic & golangci-lint Drill¶
staticcheck SA1019(deprecated reflect APIs),gocritic: hugeParam. The pattern of acceptinganythen immediately callingreflect.ValueOfis a smell-prefer typed APIs whenever possible.
13.5 Production Hardening Slice¶
- Add a benchmark that captures the per-call allocation count for the validator's hot path. The hot path (validating a previously-seen type) must allocate ≤1 time. CI fails on regressions.