HowtoGo
Home / Standard Library / The reflect Package
Standard Library

The reflect Package

reflect lets a program examine types it was not written against: the fields of a struct, the kind of a value, the tag on a field. It is what encoding/json is built from.

Examples

Every value has a type, and every type falls into one of a fixed set of kinds. Kind is the question worth asking, because a named type like type ID int still reports Int.

for _, v := range []any{42, "go", 3.5, []int{1}, map[string]int{}, User{}} {
    t := reflect.TypeOf(v)
    fmt.Println(t, "->", t.Kind())
}
Output
int -> int
string -> string
float64 -> float64
[]int -> slice
map[string]int -> map
main.User -> struct
FunctionDescription
TypeOf(i any) Type
reflect.TypeOf(42).Kind() // reflect.Int
The dynamic type of a value, as something you can ask questions about.
ValueOf(i any) Value
reflect.ValueOf("go").Len() // 2
The value itself, wrapped so it can be read and sometimes written.
Value.Elem() Value
What a pointer or interface points at.
Type.Kind() Kind
t.Kind() == reflect.Slice
Which of Go's built-in categories the type falls into.
Type.Name() string
t.Name() // "User"
The declared name, empty for an unnamed type like []int.
Type.NumField() int
t.NumField() // 3
How many fields a struct type has. Panics on anything else.
Type.Field(i int) StructField
t.Field(0).Name // "Name"
One field's name, type, tag, and whether it is exported.
Type.NumMethod() int
t.NumMethod()
How many exported methods the type has.
Type.Implements(u Type) bool
t.Implements(errType)
Whether the type satisfies an interface.
Value.Interface() any
v.Interface().(string)
The value back as an ordinary any, ready to type-assert.
Value.FieldByName(name string) Value
v.FieldByName("Email")
One struct field by name, zero Value if there is no such field.
Value.CanSet() bool
v.Field(0).CanSet() // false on a copy
Whether writing to this value would work.
Value.SetString(s string)
v.FieldByName("Name").SetString("Ada")
Writes a string. Panics unless CanSet is true and the kind matches.
Value.SetInt(x int64)
v.SetInt(7)
Writes any signed integer kind.
Value.Set(x Value)
v.Set(reflect.ValueOf(other))
Writes another Value, which must be assignable to this one.
Value.IsZero() bool
v.IsZero()
Whether the value is its type's zero value.
Value.IsNil() bool
v.IsNil()
Whether a pointer, slice, map, channel, func or interface is nil.
DeepEqual(x, y any) bool
reflect.DeepEqual(a, b) // true
Compares two values recursively, including maps and slices.
Zero(t Type) Value
reflect.Zero(t)
A new zero value of the given type.
New(t Type) Value
reflect.New(t).Elem()
A pointer to a new zero value, the reflective form of new(T).
MakeSlice(t Type, len, cap int) Value
reflect.MakeSlice(t, 0, 4)
A new slice of the given type, length and capacity.
Kind
The category of a type: Int, String, Slice, Map, Struct, Ptr, Func, Chan, Interface, and the rest.
StructField
One field of a struct type: Name, Type, Tag, Index, and Anonymous for an embedded field.
StructTag
f.Tag.Get("json") // "name,omitempty"
The string in backticks after a field. Get returns one key's value, Lookup reports whether it was there.
Before reaching for it

Reflection moves errors from compile time to run time. A misspelled field name is a panic in production rather than a message from the compiler, and the code is slower and harder to follow.

Most of what people reach for it can be done with a type assertion, a type switch, or an interface. It earns its place when the types genuinely are not known while you are writing the code: a decoder, a test helper comparing arbitrary values, an ORM mapping rows onto structs.