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().