Reflection in Practice

Overview

The reflect package provides runtime type inspection. Use sparingly—prefer generics or interfaces when possible.

Type and Value

import "reflect"

x := 42
t := reflect.TypeOf(x)   // Type information
v := reflect.ValueOf(x)  // Value information

fmt.Println(t.Name())    // int
fmt.Println(t.Kind())    // int
fmt.Println(v.Int())     // 42

Inspecting Structs

type User struct {
    Name  string `json:"name"`
    Email string `json:"email"`
}

u := User{Name: "Alice", Email: "a@b.com"}
t := reflect.TypeOf(u)
v := reflect.ValueOf(u)

for i := 0; i < t.NumField(); i++ {
    field := t.Field(i)
    value := v.Field(i)
    tag := field.Tag.Get("json")
    fmt.Printf("%s: %v (tag: %s)\n", field.Name, value, tag)
}

Modifying Values

x := 42
v := reflect.ValueOf(&x).Elem()  // Need pointer for modification
v.SetInt(100)
fmt.Println(x)  // 100

Calling Methods

type Calculator struct{}
func (c Calculator) Add(a, b int) int { return a + b }

c := Calculator{}
v := reflect.ValueOf(c)
method := v.MethodByName("Add")
args := []reflect.Value{reflect.ValueOf(2), reflect.ValueOf(3)}
result := method.Call(args)
fmt.Println(result[0].Int())  // 5

When to Use

Appropriate: - Serialization/deserialization - ORM mapping - Dependency injection - Test utilities

Avoid: - Performance-critical paths - Simple type conversions - When generics suffice

Summary

Function Purpose
TypeOf() Get type info
ValueOf() Get value wrapper
Kind() Base type category
Field() Access struct field
MethodByName() Access method