Reflection with the reflect Package
Reflection lets a program inspect and modify values whose types it doesn't know at compile time. You'll use reflect.TypeOf and ValueOf , tell Kind from Type , read struct tags the way encoding/json does, set fields via Elem and CanSet , call methods dynamically — and learn the three laws and when not to use it.
Learn Reflection with the reflect Package in our free Go course — an interactive lesson with worked examples, a practice exercise and a quick reference.
Part of the free Go course at LearnCodingFast — hands-on lessons with examples you run in your browser, plus practice exercises and a quick quiz.
What You'll Learn in This Lesson
1️⃣ TypeOf , ValueOf , and Kind
reflect.TypeOf gives a reflect.Type ; reflect.ValueOf gives a reflect.Value . The Kind is the broad category (int, slice, struct), distinct from the specific named Type .
2️⃣ Inspecting struct fields and tags
Loop over a struct's fields with NumField and Field(i) , then read tags with f.Tag.Get("json") . This is precisely how encoding/json maps fields to JSON keys.
3️⃣ Settability: Elem and CanSet
reflect.ValueOf(x) is a copy and not settable. To modify the original, pass a pointer and call Elem() to reach the addressable value — then CanSet() is true.
4️⃣ Calling methods dynamically
Value.MethodByName looks up a method at runtime, and Call invokes it with a []reflect.Value of arguments, returning the results the same way.
🎯 Your Turn
Inspect a struct. Fill in the two blanks marked ___ to count fields and read the first field's json tag.
❌ Calling SetX on reflect.ValueOf(x) — panics (not settable).
✅ Pass &x and use .Elem() to get a settable Value.
❌ Reflecting on unexported fields and trying to set them — panics.
✅ Only set exported (capitalized) fields; check CanSet() .
❌ Confusing Kind with Type — a named int has Kind Int.
✅ Use Kind() for category, Type for the exact type.
❌ Reaching for reflection by default — slow and unsafe.
✅ Prefer interfaces or generics; use reflection only when truly dynamic.
Pass a pointer and call Elem() . Then it is addressable and CanSet() is true.
encoding/json via reflection — field.Tag.Get("json") maps a Go field to its JSON key.
Take a *Config , get a settable value with Elem() , and set Host and Port by name with FieldByName .
Practice quiz
What does reflect.TypeOf(x) return?
- a reflect.Type describing x's dynamic type
- the string name only
- a reflect.Value
- the size of x in bytes
Answer: a reflect.Type describing x's dynamic type. reflect.TypeOf returns a reflect.Type; reflect.ValueOf returns a reflect.Value holding the runtime value.
What is the difference between a Type's Kind and its Type?
- Type is always 'interface'
- they are always identical
- Kind is the underlying category (struct, int, slice...); Type is the specific named type
- Kind is the package name
Answer: Kind is the underlying category (struct, int, slice...); Type is the specific named type. Kind is the broad category like reflect.Struct or reflect.Int; the Type can be a specific named type such as time.Duration whose Kind is Int64.
How do you read a struct field's tag with reflect?
- v.Tag()
- field.Tag.Get("json") on the StructField
- reflect.Tag(v)
- v.Field(0).Tag
Answer: field.Tag.Get("json") on the StructField. t.Field(i) returns a reflect.StructField whose Tag.Get("json") reads the json tag value, exactly how encoding/json finds keys.
What does the Elem() method do on a pointer's reflect.Value?
- deletes the value
- returns the element type's name only
- returns the pointer's address
- returns the Value that the pointer points to
Answer: returns the Value that the pointer points to. For a pointer Value, Elem() dereferences it to the pointed-to Value; on a Type it gives the element/base type.
For CanSet() to be true, the value must be...
- addressable and exported, typically reached via a pointer's Elem()
- of kind Int only
- a constant
- obtained from reflect.ValueOf(x) directly
Answer: addressable and exported, typically reached via a pointer's Elem(). You can only set addressable, exported fields; pass a pointer and use Elem() so the Value is settable (CanSet() == true).
Which package famously uses struct tags via reflection?
- os
- encoding/json
- sort
- fmt
Answer: encoding/json. encoding/json reads the json struct tags through reflection to map Go fields to JSON keys.
How do you call a method dynamically by name?
- reflect.Call(v, name)
- v.Invoke(name)
- v.Method(name)()
- v.MethodByName("Greet").Call(args)
Answer: v.MethodByName("Greet").Call(args). Value.MethodByName returns a callable Value; Call takes a []reflect.Value of arguments and returns the results.
Which is one of the 'three laws of reflection'?
- Reflection only works on pointers
- Reflection disables the garbage collector
- Reflection goes from interface value to reflection object and back
- Reflection always copies the value
Answer: Reflection goes from interface value to reflection object and back. The laws are: reflection goes from interface to reflection object; from reflection object back to interface; and a Value is settable only if it is addressable/exported.
Why should reflection usually be a LAST resort?
- it is not in the standard library
- it bypasses compile-time type checks and is slower and harder to read
- it only works in tests
- it cannot read structs
Answer: it bypasses compile-time type checks and is slower and harder to read. Reflection sidesteps static typing, costs performance, and can panic at runtime; prefer interfaces or generics when they fit.
What happens if you call Value.SetInt on a non-settable Value?
- it panics at runtime
- it converts the value to a string
- it silently does nothing
- it returns an error
Answer: it panics at runtime. Setting a non-addressable/non-settable Value panics; always check CanSet() first or obtain the Value via a pointer's Elem().